Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ set(BOOST_SRC_DIR ${DEFAULT_BOOST_SRC_DIR} CACHE STRING "Boost source dir to use
# The boost super-project requires one explicit dependency per-line.
set(BOOST_WS_PROTO_DEPENDENCIES
Boost::http_proto
Boost::url
)

foreach (BOOST_WS_PROTO_DEPENDENCY ${BOOST_WS_PROTO_DEPENDENCIES})
Expand Down Expand Up @@ -126,13 +127,14 @@ endif ()
#-------------------------------------------------
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

file(GLOB_RECURSE BOOST_WS_PROTO_HEADERS CONFIGURE_DEPENDS include/boost/*.hpp include/boost/*.natvis)
file(GLOB_RECURSE BOOST_WS_PROTO_HEADERS CONFIGURE_DEPENDS include/boost/ws_proto/*.hpp include/boost/ws_proto/*.natvis)
file(GLOB_RECURSE BOOST_WS_PROTO_SOURCES CONFIGURE_DEPENDS src/*.cpp src/*.hpp)

source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/include/boost PREFIX "" FILES ${BOOST_WS_PROTO_HEADERS})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/src PREFIX "ws_proto" FILES ${BOOST_WS_PROTO_SOURCES})
source_group("" FILES "include/boost/ws_proto.hpp" "build/Jamfile")
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/include/boost/ws_proto PREFIX "include" FILES ${BOOST_WS_PROTO_HEADERS})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/src PREFIX "src" FILES ${BOOST_WS_PROTO_SOURCES})

add_library(boost_ws_proto ${BOOST_WS_PROTO_HEADERS} ${BOOST_WS_PROTO_SOURCES})
add_library(boost_ws_proto include/boost/ws_proto.hpp build/Jamfile ${BOOST_WS_PROTO_HEADERS} ${BOOST_WS_PROTO_SOURCES})
add_library(Boost::ws_proto ALIAS boost_ws_proto)
target_compile_features(boost_ws_proto PUBLIC cxx_constexpr)
target_include_directories(boost_ws_proto PUBLIC "${PROJECT_SOURCE_DIR}/include")
Expand Down
1 change: 1 addition & 0 deletions build/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ lib boost_ws_proto
: requirements
<library>/boost//buffers
<library>/boost//http_proto
<library>/boost//url
<include>../
<define>BOOST_WS_PROTO_SOURCE
: usage-requirements
Expand Down
44 changes: 44 additions & 0 deletions include/boost/ws_proto/client.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/cppalliance/ws_proto
//

#ifndef BOOST_WS_PROTO_CLIENT_HPP
#define BOOST_WS_PROTO_CLIENT_HPP

#include <boost/ws_proto/detail/config.hpp>

namespace boost {
namespace ws_proto {

enum class frame_type
{
ping,
pong,
close,
cont,
data
};

/** A WebSocket client
*/
class client
{
public:
/** Add an outgoing frame
*/
template<class ConstBufferSequence>
bool
write(
frame_type kind,
ConstBufferSequence const& payload);
};

} // ws_proto
} // boost

#endif
2 changes: 2 additions & 0 deletions include/boost/ws_proto/handshake.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ system::result<bool>
is_upgrade(
http_proto::request_view const& req) noexcept;

/** Return a Websocket Upgrade HTTP request
*/
BOOST_WS_PROTO_DECL
http_proto::request
make_upgrade(
Expand Down
29 changes: 29 additions & 0 deletions src/handshake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//

#include <boost/ws_proto/handshake.hpp>
#include "src/impl/hybi13.hpp"

namespace boost {
namespace ws_proto {
Expand All @@ -19,5 +20,33 @@ is_upgrade(
return false;
}

http_proto::request
make_upgrade(
urls::url_view target)
{
http_proto::request req;
req.set_start_line(
http_proto::method::get,
target.buffer(),
http_proto::version::http_1_1);
req.set(http_proto::field::host, "host");
req.set(http_proto::field::connection, "Upgrade");
req.set(http_proto::field::upgrade, "websocket");

detail::request_key key;
detail::make_request_key(key);
req.set(http_proto::field::sec_websocket_key,
core::string_view(key.data, key.size));
req.set(http_proto::field::sec_websocket_version, "13");

/*
this->build_request_pmd(req);
decorator_opt(req);
decorator(req);
*/

return req;
}

} // ws_proto
} // boost
179 changes: 179 additions & 0 deletions src/impl/base64.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/cppalliance/ws_proto
//

/*
Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
Copyright notice:

base64.cpp and base64.h

Copyright (C) 2004-2008 Rene Nyffenegger

This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.

3. This notice may not be removed or altered from any source distribution.

Rene Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/

#include "src/impl/base64.hpp"
#include <cctype>
#include <string>
#include <utility>

namespace boost {
namespace ws_proto {

char const*
base64_alphabet() noexcept
{
static char constexpr tab[] = {
"ABCDEFGHIJKLMNOP"
"QRSTUVWXYZabcdef"
"ghijklmnopqrstuv"
"wxyz0123456789+/"
};
return &tab[0];
}

signed char const*
base64_inverse() noexcept
{
static signed char constexpr tab[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 48-63
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255
};
return &tab[0];
}

/** Encode a series of octets as a padded, base64 string.

The resulting string will not be null terminated.

@par Requires

The memory pointed to by `out` points to valid memory
of at least `encoded_size(len)` bytes.

@return The number of characters written to `out`. This
will exclude any null termination.
*/
std::size_t
base64_encode(void* dest, void const* src, std::size_t len)
{
char* out = static_cast<char*>(dest);
char const* in = static_cast<char const*>(src);
auto const tab = base64_alphabet();

for(auto n = len / 3; n--;)
{
*out++ = tab[ (in[0] & 0xfc) >> 2];
*out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];
*out++ = tab[((in[2] & 0xc0) >> 6) + ((in[1] & 0x0f) << 2)];
*out++ = tab[ in[2] & 0x3f];
in += 3;
}

switch(len % 3)
{
case 2:
*out++ = tab[ (in[0] & 0xfc) >> 2];
*out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];
*out++ = tab[ (in[1] & 0x0f) << 2];
*out++ = '=';
break;

case 1:
*out++ = tab[ (in[0] & 0xfc) >> 2];
*out++ = tab[((in[0] & 0x03) << 4)];
*out++ = '=';
*out++ = '=';
break;

case 0:
break;
}

return out - static_cast<char*>(dest);
}

std::pair<std::size_t, std::size_t>
base64_decode(void* dest, char const* src, std::size_t len)
{
char* out = static_cast<char*>(dest);
auto in = reinterpret_cast<unsigned char const*>(src);
unsigned char c3[3], c4[4] = {0,0,0,0};
int i = 0;
int j = 0;

auto const inverse = base64_inverse();

while(len-- && *in != '=')
{
auto const v = inverse[*in];
if(v == -1)
break;
++in;
c4[i] = v;
if(++i == 4)
{
c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];

for(i = 0; i < 3; i++)
*out++ = c3[i];
i = 0;
}
}

if(i)
{
c3[0] = ( c4[0] << 2) + ((c4[1] & 0x30) >> 4);
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];

for(j = 0; j < i - 1; j++)
*out++ = c3[j];
}

return {out - static_cast<char*>(dest),
in - reinterpret_cast<unsigned char const*>(src)};
}

} // ws_proto
} // boost
73 changes: 73 additions & 0 deletions src/impl/base64.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// Copyright (c) 2016-2025 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/cppalliance/ws_proto
//

#ifndef BOOST_WS_PROTO_SRC_IMPL_BASE64_HPP
#define BOOST_WS_PROTO_SRC_IMPL_BASE64_HPP

#include <cctype>
#include <utility>

namespace boost {
namespace ws_proto {

char const*
base64_alphabet() noexcept;

signed char const*
base64_inverse() noexcept;

/// Returns max chars needed to encode a base64 string
std::size_t
constexpr
base64_encoded_size(std::size_t n)
{
return 4 * ((n + 2) / 3);
}

/// Returns max bytes needed to decode a base64 string
std::size_t
constexpr
base64_decoded_size(std::size_t n)
{
return n / 4 * 3; // requires n&3==0, smaller
}

/** Encode a series of octets as a padded, base64 string.

The resulting string will not be null terminated.

@par Requires

The memory pointed to by `out` points to valid memory
of at least `encoded_size(len)` bytes.

@return The number of characters written to `out`. This
will exclude any null termination.
*/
std::size_t
base64_encode(void* dest, void const* src, std::size_t len);

/** Decode a padded base64 string into a series of octets.

@par Requires

The memory pointed to by `out` points to valid memory
of at least `decoded_size(len)` bytes.

@return The number of octets written to `out`, and
the number of characters read from the input string,
expressed as a pair.
*/
std::pair<std::size_t, std::size_t>
base64_decode(void* dest, char const* src, std::size_t len);

} // ws_proto
} // boost

#endif
Loading
Loading