Squashed 'src/beast/' changes from 1b9a714..6d5547a

6d5547a Set version to 1.0.0-b34
6fab138 Fix and tidy up CMake build scripts:
ccefa54 Set version to 1.0.0-b33
32afe41 Set internal state correctly when writing frames:
fe3e20b Add write_frames unit test
578dcd0 Add decorator unit test
aaa3733 Use fwrite return value in file_body
df66165 Require Visual Studio 2015 Update 3 or later
b8e5a21 Set version to 1.0.0-b32
ffb1758 Update CMake scripts for finding packages:
b893749 Remove http Writer suspend and resume feature (API Change):
27864fb Add io_service completion invariants tests
eba05a7 Set version to 1.0.0-b31
484bcef Fix badge markdown in README.md
5663bea Add missing dynabuf_readstream member
0d7a551 Tidy up build settings
0fd4030 Move the handler, don't copy it

git-subtree-dir: src/beast
git-subtree-split: 6d5547a32c50ec95832c4779311502555ab0ee1f
This commit is contained in:
Vinnie Falco
2017-04-20 13:40:52 -07:00
parent 9bb337fb1f
commit d8dea963fa
3303 changed files with 940 additions and 952605 deletions

27
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,27 @@
# Part of Beast
GroupSources(extras/beast extras)
GroupSources(include/beast beast)
GroupSources(test "/")
add_executable (lib-tests
${BEAST_INCLUDES}
${EXTRAS_INCLUDES}
../extras/beast/unit_test/main.cpp
config.cpp
core.cpp
http.cpp
version.cpp
websocket.cpp
zlib.cpp
)
if (NOT WIN32)
target_link_libraries(lib-tests ${Boost_LIBRARIES} Threads::Threads)
else()
target_link_libraries(lib-tests ${Boost_LIBRARIES})
endif()
if (MINGW)
set_target_properties(lib-tests PROPERTIES COMPILE_FLAGS "-Wa,-mbig-obj")
endif()

103
test/Jamfile Normal file
View File

@@ -0,0 +1,103 @@
#
# Copyright (c) 2013-2017 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)
#
import os ;
compile config.cpp : : ;
compile core.cpp : : ;
compile http.cpp : : ;
compile version.cpp : : ;
compile websocket.cpp : : ;
compile zlib.cpp : : ;
unit-test core-tests :
../extras/beast/unit_test/main.cpp
core/async_completion.cpp
core/bind_handler.cpp
core/buffer_cat.cpp
core/buffer_concepts.cpp
core/buffers_adapter.cpp
core/clamp.cpp
core/consuming_buffers.cpp
core/dynabuf_readstream.cpp
core/error.cpp
core/handler_alloc.cpp
core/handler_concepts.cpp
core/handler_ptr.cpp
core/placeholders.cpp
core/prepare_buffer.cpp
core/prepare_buffers.cpp
core/static_streambuf.cpp
core/static_string.cpp
core/stream_concepts.cpp
core/streambuf.cpp
core/to_string.cpp
core/write_dynabuf.cpp
core/base64.cpp
core/empty_base_optimization.cpp
core/get_lowest_layer.cpp
core/is_call_possible.cpp
core/sha1.cpp
;
unit-test http-tests :
../extras/beast/unit_test/main.cpp
http/basic_dynabuf_body.cpp
http/basic_fields.cpp
http/basic_parser_v1.cpp
http/concepts.cpp
http/empty_body.cpp
http/fields.cpp
http/header_parser_v1.cpp
http/message.cpp
http/parse.cpp
http/parse_error.cpp
http/parser_v1.cpp
http/read.cpp
http/reason.cpp
http/rfc7230.cpp
http/streambuf_body.cpp
http/string_body.cpp
http/write.cpp
http/chunk_encode.cpp
;
unit-test bench-tests :
../extras/beast/unit_test/main.cpp
http/nodejs_parser.cpp
http/parser_bench.cpp
;
unit-test websocket-tests :
../extras/beast/unit_test/main.cpp
websocket/error.cpp
websocket/option.cpp
websocket/rfc6455.cpp
websocket/stream.cpp
websocket/teardown.cpp
websocket/frame.cpp
websocket/mask.cpp
websocket/utf8_checker.cpp
;
unit-test zlib-tests :
../extras/beast/unit_test/main.cpp
zlib/zlib-1.2.8/adler32.c
zlib/zlib-1.2.8/compress.c
zlib/zlib-1.2.8/crc32.c
zlib/zlib-1.2.8/deflate.c
zlib/zlib-1.2.8/infback.c
zlib/zlib-1.2.8/inffast.c
zlib/zlib-1.2.8/inflate.c
zlib/zlib-1.2.8/inftrees.c
zlib/zlib-1.2.8/trees.c
zlib/zlib-1.2.8/uncompr.c
zlib/zlib-1.2.8/zutil.c
zlib/deflate_stream.cpp
zlib/error.cpp
zlib/inflate_stream.cpp
;

9
test/config.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/config.hpp>

9
test/core.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core.hpp>

44
test/core/CMakeLists.txt Normal file
View File

@@ -0,0 +1,44 @@
# Part of Beast
GroupSources(extras/beast extras)
GroupSources(include/beast beast)
GroupSources(test/core "/")
add_executable (core-tests
${BEAST_INCLUDES}
${EXTRAS_INCLUDES}
../../extras/beast/unit_test/main.cpp
buffer_test.hpp
async_completion.cpp
bind_handler.cpp
buffer_cat.cpp
buffer_concepts.cpp
buffers_adapter.cpp
clamp.cpp
consuming_buffers.cpp
dynabuf_readstream.cpp
error.cpp
handler_alloc.cpp
handler_concepts.cpp
handler_ptr.cpp
placeholders.cpp
prepare_buffer.cpp
prepare_buffers.cpp
static_streambuf.cpp
static_string.cpp
stream_concepts.cpp
streambuf.cpp
to_string.cpp
write_dynabuf.cpp
base64.cpp
empty_base_optimization.cpp
get_lowest_layer.cpp
is_call_possible.cpp
sha1.cpp
)
if (NOT WIN32)
target_link_libraries(core-tests ${Boost_LIBRARIES} Threads::Threads)
else()
target_link_libraries(core-tests ${Boost_LIBRARIES})
endif()

View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/async_completion.hpp>

44
test/core/base64.cpp Normal file
View File

@@ -0,0 +1,44 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/detail/base64.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace detail {
class base64_test : public beast::unit_test::suite
{
public:
void
check (std::string const& in, std::string const& out)
{
auto const encoded = base64_encode (in);
BEAST_EXPECT(encoded == out);
BEAST_EXPECT(base64_decode (encoded) == in);
}
void
run()
{
check ("", "");
check ("f", "Zg==");
check ("fo", "Zm8=");
check ("foo", "Zm9v");
check ("foob", "Zm9vYg==");
check ("fooba", "Zm9vYmE=");
check ("foobar", "Zm9vYmFy");
}
};
BEAST_DEFINE_TESTSUITE(base64,core,beast);
} // detail
} // beast

View File

@@ -0,0 +1,37 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/bind_handler.hpp>
#include <beast/unit_test/suite.hpp>
#include <functional>
namespace beast {
class bind_handler_test : public unit_test::suite
{
public:
void
callback(int v)
{
BEAST_EXPECT(v == 42);
}
void run()
{
auto f = bind_handler(std::bind(
&bind_handler_test::callback, this,
std::placeholders::_1), 42);
f();
pass();
}
};
BEAST_DEFINE_TESTSUITE(bind_handler,core,beast);
} // beast

271
test/core/buffer_cat.cpp Normal file
View File

@@ -0,0 +1,271 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/buffer_cat.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/streambuf.hpp>
#include <iterator>
#include <list>
#include <type_traits>
#include <vector>
namespace beast {
class buffer_cat_test : public unit_test::suite
{
public:
template<class Iterator>
static
std::reverse_iterator<Iterator>
make_reverse_iterator(Iterator i)
{
return std::reverse_iterator<Iterator>(i);
}
template<class ConstBufferSequence>
static
std::size_t
bsize1(ConstBufferSequence const& bs)
{
using boost::asio::buffer_size;
std::size_t n = 0;
for(auto it = bs.begin(); it != bs.end(); ++it)
n += buffer_size(*it);
return n;
}
template<class ConstBufferSequence>
static
std::size_t
bsize2(ConstBufferSequence const& bs)
{
using boost::asio::buffer_size;
std::size_t n = 0;
for(auto it = bs.begin(); it != bs.end(); it++)
n += buffer_size(*it);
return n;
}
template<class ConstBufferSequence>
static
std::size_t
bsize3(ConstBufferSequence const& bs)
{
using boost::asio::buffer_size;
std::size_t n = 0;
for(auto it = bs.end(); it != bs.begin();)
n += buffer_size(*--it);
return n;
}
template<class ConstBufferSequence>
static
std::size_t
bsize4(ConstBufferSequence const& bs)
{
using boost::asio::buffer_size;
std::size_t n = 0;
for(auto it = bs.end(); it != bs.begin();)
{
it--;
n += buffer_size(*it);
}
return n;
}
void testBufferCat()
{
using boost::asio::buffer_size;
using boost::asio::const_buffer;
char buf[10];
std::list<const_buffer> b1;
std::vector<const_buffer> b2{
const_buffer{buf+0, 1},
const_buffer{buf+1, 2}};
std::list<const_buffer> b3;
std::array<const_buffer, 3> b4{{
const_buffer{buf+3, 1},
const_buffer{buf+4, 2},
const_buffer{buf+6, 3}}};
std::list<const_buffer> b5{
const_buffer{buf+9, 1}};
std::list<const_buffer> b6;
auto bs = buffer_cat(
b1, b2, b3, b4, b5, b6);
BEAST_EXPECT(buffer_size(bs) == 10);
BEAST_EXPECT(bsize1(bs) == 10);
BEAST_EXPECT(bsize2(bs) == 10);
BEAST_EXPECT(bsize3(bs) == 10);
BEAST_EXPECT(bsize4(bs) == 10);
std::vector<const_buffer> v;
for(auto iter = make_reverse_iterator(bs.end());
iter != make_reverse_iterator(bs.begin()); ++iter)
v.emplace_back(*iter);
BEAST_EXPECT(buffer_size(bs) == 10);
decltype(bs) bs2(bs);
auto bs3(std::move(bs));
{
boost::asio::streambuf sb1, sb2;
BEAST_EXPECT(buffer_size(buffer_cat(
sb1.prepare(5), sb2.prepare(7))) == 12);
sb1.commit(5);
sb2.commit(7);
BEAST_EXPECT(buffer_size(buffer_cat(
sb1.data(), sb2.data())) == 12);
}
for(auto it = bs.begin(); it != bs.end(); ++it)
{
decltype(bs)::const_iterator copy;
copy = it;
BEAST_EXPECT(copy == it);
copy = copy;
BEAST_EXPECT(copy == it);
}
}
void testIterators()
{
using boost::asio::buffer_size;
using boost::asio::const_buffer;
char buf[9];
std::vector<const_buffer> b1{
const_buffer{buf+0, 1},
const_buffer{buf+1, 2}};
std::array<const_buffer, 3> b2{{
const_buffer{buf+3, 1},
const_buffer{buf+4, 2},
const_buffer{buf+6, 3}}};
auto bs = buffer_cat(b1, b2);
for(int n = 0;
n <= std::distance(bs.begin(), bs.end()); ++n)
{
auto it = std::next(bs.begin(), n);
decltype(it) it2(std::move(it));
it = std::move(it2);
auto pit = &it;
it = std::move(*pit);
}
try
{
std::size_t n = 0;
for(auto it = bs.begin(); n < 100; ++it)
++n;
fail();
}
catch(std::exception const&)
{
pass();
}
// decrement iterator
{
auto const rbegin =
make_reverse_iterator(bs.end());
auto const rend =
make_reverse_iterator(bs.begin());
std::size_t n = 0;
for(auto it = rbegin; it != rend; ++it)
n += buffer_size(*it);
BEAST_EXPECT(n == 9);
}
try
{
std::size_t n = 0;
for(auto it = bs.end(); n < 100; --it)
++n;
fail();
}
catch(std::exception const&)
{
pass();
}
try
{
buffer_size(*bs.end());
fail();
}
catch(std::exception const&)
{
pass();
}
auto bs2 = bs;
BEAST_EXPECT(bs.begin() != bs2.begin());
BEAST_EXPECT(bs.end() != bs2.end());
decltype(bs)::const_iterator it;
decltype(bs2)::const_iterator it2;
BEAST_EXPECT(it == it2);
}
void run() override
{
using boost::asio::const_buffer;
using boost::asio::const_buffers_1;
using boost::asio::mutable_buffer;
using boost::asio::mutable_buffers_1;
struct user_defined : mutable_buffer
{
};
// Check is_all_ConstBufferSequence
static_assert(
detail::is_all_ConstBufferSequence<
const_buffers_1
>::value, "");
static_assert(
detail::is_all_ConstBufferSequence<
const_buffers_1, const_buffers_1
>::value, "");
static_assert(
detail::is_all_ConstBufferSequence<
mutable_buffers_1
>::value, "");
static_assert(
detail::is_all_ConstBufferSequence<
mutable_buffers_1, mutable_buffers_1
>::value, "");
static_assert(
detail::is_all_ConstBufferSequence<
const_buffers_1, mutable_buffers_1
>::value, "");
static_assert(
! detail::is_all_ConstBufferSequence<
const_buffers_1, mutable_buffers_1, int
>::value, "");
// Ensure that concatenating mutable buffer
// sequences results in a mutable buffer sequence
static_assert(std::is_same<
mutable_buffer,
decltype(buffer_cat(
std::declval<mutable_buffer>(),
std::declval<user_defined>(),
std::declval<mutable_buffer>()
))::value_type>::value, "");
// Ensure that concatenating mixed buffer
// sequences results in a const buffer sequence.
static_assert(std::is_same<
const_buffer,
decltype(buffer_cat(
std::declval<mutable_buffer>(),
std::declval<user_defined>(),
std::declval<const_buffer>()
))::value_type>::value, "");
testBufferCat();
testIterators();
}
};
BEAST_DEFINE_TESTSUITE(buffer_cat,core,beast);
} // beast

View File

@@ -0,0 +1,25 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/buffer_concepts.hpp>
namespace beast {
namespace {
struct T
{
};
}
static_assert(is_ConstBufferSequence<detail::ConstBufferSequence>::value, "");
static_assert(! is_ConstBufferSequence<T>::value, "");
static_assert(is_MutableBufferSequence<detail::MutableBufferSequence>::value, "");
static_assert(! is_MutableBufferSequence<T>::value, "");
} // beast

89
test/core/buffer_test.hpp Normal file
View File

@@ -0,0 +1,89 @@
//
// Copyright (c) 2013-2017 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)
//
#ifndef BEAST_TEST_BUFFER_TEST_HPP
#define BEAST_TEST_BUFFER_TEST_HPP
#include <beast/core/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <type_traits>
namespace beast {
namespace test {
template<class ConstBufferSequence>
typename std::enable_if<
is_ConstBufferSequence<ConstBufferSequence>::value,
std::size_t>::type
buffer_count(ConstBufferSequence const& buffers)
{
return std::distance(buffers.begin(), buffers.end());
}
template<class ConstBufferSequence>
typename std::enable_if<
is_ConstBufferSequence<ConstBufferSequence>::value,
std::size_t>::type
size_pre(ConstBufferSequence const& buffers)
{
std::size_t n = 0;
for(auto it = buffers.begin(); it != buffers.end(); ++it)
{
typename ConstBufferSequence::const_iterator it0(std::move(it));
typename ConstBufferSequence::const_iterator it1(it0);
typename ConstBufferSequence::const_iterator it2;
it2 = it1;
n += boost::asio::buffer_size(*it2);
it = std::move(it2);
}
return n;
}
template<class ConstBufferSequence>
typename std::enable_if<
is_ConstBufferSequence<ConstBufferSequence>::value,
std::size_t>::type
size_post(ConstBufferSequence const& buffers)
{
std::size_t n = 0;
for(auto it = buffers.begin(); it != buffers.end(); it++)
n += boost::asio::buffer_size(*it);
return n;
}
template<class ConstBufferSequence>
typename std::enable_if<
is_ConstBufferSequence<ConstBufferSequence>::value,
std::size_t>::type
size_rev_pre(ConstBufferSequence const& buffers)
{
std::size_t n = 0;
for(auto it = buffers.end(); it != buffers.begin();)
n += boost::asio::buffer_size(*--it);
return n;
}
template<class ConstBufferSequence>
typename std::enable_if<
is_ConstBufferSequence<ConstBufferSequence>::value,
std::size_t>::type
size_rev_post(ConstBufferSequence const& buffers)
{
std::size_t n = 0;
for(auto it = buffers.end(); it != buffers.begin();)
{
it--;
n += boost::asio::buffer_size(*it);
}
return n;
}
} // test
} // beast
#endif

View File

@@ -0,0 +1,190 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/buffers_adapter.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/streambuf.hpp>
#include <iterator>
namespace beast {
class buffers_adapter_test : public unit_test::suite
{
public:
template<class ConstBufferSequence>
static
std::string
to_string(ConstBufferSequence const& bs)
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
std::string s;
s.reserve(buffer_size(bs));
for(auto const& b : bs)
s.append(buffer_cast<char const*>(b),
buffer_size(b));
return s;
}
void testBuffersAdapter()
{
using boost::asio::buffer;
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
using boost::asio::const_buffer;
using boost::asio::mutable_buffer;
char buf[12];
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == sizeof(buf));
for(std::size_t i = 1; i < 4; ++i) {
for(std::size_t j = 1; j < 4; ++j) {
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
for(std::size_t t = 1; t < 4; ++ t) {
for(std::size_t u = 1; u < 4; ++ u) {
std::size_t k = sizeof(buf) - (i + j);
std::size_t z = sizeof(buf) - (x + y);
std::size_t v = sizeof(buf) - (t + u);
{
std::memset(buf, 0, sizeof(buf));
std::array<mutable_buffer, 3> bs{{
mutable_buffer{&buf[0], i},
mutable_buffer{&buf[i], j},
mutable_buffer{&buf[i+j], k}}};
buffers_adapter<decltype(bs)> ba(std::move(bs));
BEAST_EXPECT(ba.max_size() == sizeof(buf));
{
auto d = ba.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
ba.commit(buffer_copy(d, buffer(s.data(), x)));
}
BEAST_EXPECT(ba.size() == x);
BEAST_EXPECT(ba.max_size() == sizeof(buf) - x);
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
}
ba.commit(1);
BEAST_EXPECT(ba.size() == x + y);
BEAST_EXPECT(ba.max_size() == sizeof(buf) - (x + y));
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(z); BEAST_EXPECT(buffer_size(d) == z);
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
}
ba.commit(2);
BEAST_EXPECT(ba.size() == x + y + z);
BEAST_EXPECT(ba.max_size() == 0);
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
BEAST_EXPECT(to_string(ba.data()) == s);
ba.consume(t);
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
BEAST_EXPECT(to_string(ba.data()) == s.substr(t, std::string::npos));
ba.consume(u);
BEAST_EXPECT(to_string(ba.data()) == s.substr(t + u, std::string::npos));
ba.consume(v);
BEAST_EXPECT(to_string(ba.data()) == "");
ba.consume(1);
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
try
{
ba.prepare(1);
fail();
}
catch(...)
{
pass();
}
}
}}}}}}
}
void testCommit()
{
using boost::asio::buffer_size;
{
using sb_type = boost::asio::streambuf;
sb_type sb;
buffers_adapter<
sb_type::mutable_buffers_type> ba(sb.prepare(3));
BEAST_EXPECT(buffer_size(ba.prepare(3)) == 3);
ba.commit(2);
BEAST_EXPECT(buffer_size(ba.data()) == 2);
}
{
using sb_type = beast::streambuf;
sb_type sb(2);
sb.prepare(3);
buffers_adapter<
sb_type::mutable_buffers_type> ba(sb.prepare(8));
BEAST_EXPECT(buffer_size(ba.prepare(8)) == 8);
ba.commit(2);
BEAST_EXPECT(buffer_size(ba.data()) == 2);
ba.consume(1);
ba.commit(6);
ba.consume(2);
BEAST_EXPECT(buffer_size(ba.data()) == 5);
ba.consume(5);
}
}
void run() override
{
testBuffersAdapter();
testCommit();
}
};
BEAST_DEFINE_TESTSUITE(buffers_adapter,core,beast);
} // beast

37
test/core/clamp.cpp Normal file
View File

@@ -0,0 +1,37 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/detail/clamp.hpp>
#include <beast/unit_test/suite.hpp>
#include <climits>
namespace beast {
namespace detail {
class clamp_test : public beast::unit_test::suite
{
public:
void testClamp()
{
BEAST_EXPECT(clamp(
(std::numeric_limits<std::uint64_t>::max)()) ==
(std::numeric_limits<std::size_t>::max)());
}
void run() override
{
testClamp();
}
};
BEAST_DEFINE_TESTSUITE(clamp,core,beast);
} // detail
} // beast

View File

@@ -0,0 +1,127 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/consuming_buffers.hpp>
#include "buffer_test.hpp"
#include <beast/core/to_string.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <string>
namespace beast {
class consuming_buffers_test : public beast::unit_test::suite
{
public:
template<class BufferSequence>
static
consuming_buffers<BufferSequence>
consumed_buffers(BufferSequence const& bs, std::size_t n)
{
consuming_buffers<BufferSequence> cb(bs);
cb.consume(n);
return cb;
}
template<class Buffers1, class Buffers2>
static
bool
eq(Buffers1 const& lhs, Buffers2 const& rhs)
{
return to_string(lhs) == to_string(rhs);
}
template<class ConstBufferSequence>
void
expect_size(std::size_t n, ConstBufferSequence const& buffers)
{
BEAST_EXPECT(test::size_pre(buffers) == n);
BEAST_EXPECT(test::size_post(buffers) == n);
BEAST_EXPECT(test::size_rev_pre(buffers) == n);
BEAST_EXPECT(test::size_rev_post(buffers) == n);
}
void testMatrix()
{
using boost::asio::buffer;
using boost::asio::const_buffer;
char buf[12];
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == sizeof(buf));
buffer_copy(buffer(buf), buffer(s));
BEAST_EXPECT(to_string(buffer(buf)) == s);
for(std::size_t i = 1; i < 4; ++i) {
for(std::size_t j = 1; j < 4; ++j) {
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
std::size_t k = sizeof(buf) - (i + j);
std::size_t z = sizeof(buf) - (x + y);
{
std::array<const_buffer, 3> bs{{
const_buffer{&buf[0], i},
const_buffer{&buf[i], j},
const_buffer{&buf[i+j], k}}};
consuming_buffers<decltype(bs)> cb(bs);
BEAST_EXPECT(to_string(cb) == s);
expect_size(s.size(), cb);
cb.consume(0);
BEAST_EXPECT(eq(cb, consumed_buffers(bs, 0)));
BEAST_EXPECT(to_string(cb) == s);
expect_size(s.size(), cb);
cb.consume(x);
BEAST_EXPECT(to_string(cb) == s.substr(x));
BEAST_EXPECT(eq(cb, consumed_buffers(bs, x)));
cb.consume(y);
BEAST_EXPECT(to_string(cb) == s.substr(x+y));
BEAST_EXPECT(eq(cb, consumed_buffers(bs, x+y)));
cb.consume(z);
BEAST_EXPECT(to_string(cb) == "");
BEAST_EXPECT(eq(cb, consumed_buffers(bs, x+y+z)));
cb.consume(1);
BEAST_EXPECT(to_string(cb) == "");
BEAST_EXPECT(eq(cb, consumed_buffers(bs, x+y+z)));
}
}}}}
}
void testNullBuffers()
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
using boost::asio::null_buffers;
consuming_buffers<null_buffers> cb(
null_buffers{});
BEAST_EXPECT(buffer_size(cb) == 0);
consuming_buffers<null_buffers> cb2(
null_buffers{});
BEAST_EXPECT(buffer_copy(cb2, cb) == 0);
}
void testIterator()
{
using boost::asio::const_buffer;
std::array<const_buffer, 3> ba;
consuming_buffers<decltype(ba)> cb(ba);
std::size_t n = 0;
for(auto it = cb.end(); it != cb.begin(); --it)
++n;
BEAST_EXPECT(n == 3);
}
void run() override
{
testMatrix();
testNullBuffers();
testIterator();
}
};
BEAST_DEFINE_TESTSUITE(consuming_buffers,core,beast);
} // beast

View File

@@ -0,0 +1,142 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/dynabuf_readstream.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/test/fail_stream.hpp>
#include <beast/test/string_istream.hpp>
#include <beast/test/yield_to.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio.hpp>
namespace beast {
class dynabuf_readstream_test
: public unit_test::suite
, public test::enable_yield_to
{
using self = dynabuf_readstream_test;
public:
void testSpecialMembers()
{
using socket_type = boost::asio::ip::tcp::socket;
boost::asio::io_service ios;
{
dynabuf_readstream<socket_type, streambuf> srs(ios);
dynabuf_readstream<socket_type, streambuf> srs2(std::move(srs));
srs = std::move(srs2);
BEAST_EXPECT(&srs.get_io_service() == &ios);
BEAST_EXPECT(&srs.get_io_service() == &srs2.get_io_service());
}
{
socket_type sock(ios);
dynabuf_readstream<socket_type&, streambuf> srs(sock);
dynabuf_readstream<socket_type&, streambuf> srs2(std::move(srs));
}
}
void testRead(yield_context do_yield)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
static std::size_t constexpr limit = 100;
std::size_t n;
std::string s;
s.resize(13);
for(n = 0; n < limit; ++n)
{
test::fail_stream<
test::string_istream> fs(n, ios_, ", world!");
dynabuf_readstream<
decltype(fs)&, streambuf> srs(fs);
srs.buffer().commit(buffer_copy(
srs.buffer().prepare(5), buffer("Hello", 5)));
error_code ec;
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
if(! ec)
{
BEAST_EXPECT(s == "Hello, world!");
break;
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<
test::string_istream> fs(n, ios_, ", world!");
dynabuf_readstream<
decltype(fs)&, streambuf> srs(fs);
srs.capacity(3);
srs.buffer().commit(buffer_copy(
srs.buffer().prepare(5), buffer("Hello", 5)));
error_code ec;
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
if(! ec)
{
BEAST_EXPECT(s == "Hello, world!");
break;
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<
test::string_istream> fs(n, ios_, ", world!");
dynabuf_readstream<
decltype(fs)&, streambuf> srs(fs);
srs.buffer().commit(buffer_copy(
srs.buffer().prepare(5), buffer("Hello", 5)));
error_code ec;
boost::asio::async_read(
srs, buffer(&s[0], s.size()), do_yield[ec]);
if(! ec)
{
BEAST_EXPECT(s == "Hello, world!");
break;
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<
test::string_istream> fs(n, ios_, ", world!");
dynabuf_readstream<
decltype(fs)&, streambuf> srs(fs);
srs.capacity(3);
srs.buffer().commit(buffer_copy(
srs.buffer().prepare(5), buffer("Hello", 5)));
error_code ec;
boost::asio::async_read(
srs, buffer(&s[0], s.size()), do_yield[ec]);
if(! ec)
{
BEAST_EXPECT(s == "Hello, world!");
break;
}
}
BEAST_EXPECT(n < limit);
}
void run() override
{
testSpecialMembers();
yield_to(&self::testRead, this);
}
};
BEAST_DEFINE_TESTSUITE(dynabuf_readstream,core,beast);
} // beast

View File

@@ -0,0 +1,94 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/detail/empty_base_optimization.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace detail {
class empty_base_optimization_test
: public beast::unit_test::suite
{
public:
template<class T>
class test1
: private empty_base_optimization<T>
{
using Base = empty_base_optimization<T>;
void* m_p;
public:
explicit test1 (T const& t)
: Base (t)
{}
T& member() {return Base::member();}
T const& member() const {return Base::member();}
};
template<class T>
class test2
{
void* m_p;
T m_t;
public:
explicit test2 (T const& t)
: m_t (t)
{}
T& member() {return m_t;}
T const& member() const {return m_t;}
};
struct Empty
{
operator bool() {return true;}
};
static
bool
test_one()
{
test1<int> t1(1);
test2<int> t2(2);
static_assert(sizeof(t1) == sizeof(t2), "don't optimize for int");
if(t1.member() != 1)
return false;
if(t2.member() != 2)
return false;
return true;
}
static
bool
test_two()
{
test1<Empty> t1((Empty()));
test2<Empty> t2((Empty()));
static_assert(sizeof(t1) < sizeof(t2), "do optimize for Empty");
if(t1.member() != true)
return false;
if(t2.member() != true)
return false;
return true;
}
void
run()
{
BEAST_EXPECT(test_one());
BEAST_EXPECT(test_two());
pass();
}
};
BEAST_DEFINE_TESTSUITE(empty_base_optimization,core,beast);
} // detail
} // beast

9
test/core/error.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/error.hpp>

View File

@@ -0,0 +1,88 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/detail/get_lowest_layer.hpp>
#include <beast/unit_test/suite.hpp>
#include <type_traits>
namespace beast {
namespace detail {
class get_lowest_layer_test
: public beast::unit_test::suite
{
public:
struct F1
{
};
struct F2
{
};
template<class F>
struct F3
{
using next_layer_type =
typename std::remove_reference<F>::type;
using lowest_layer_type = typename
get_lowest_layer<next_layer_type>::type;
};
template<class F>
struct F4
{
using next_layer_type =
typename std::remove_reference<F>::type;
using lowest_layer_type = typename
get_lowest_layer<next_layer_type>::type;
};
void
run()
{
static_assert(! has_lowest_layer<F1>::value, "");
static_assert(! has_lowest_layer<F2>::value, "");
static_assert(has_lowest_layer<F3<F1>>::value, "");
static_assert(has_lowest_layer<F4<F3<F2>>>::value, "");
static_assert(std::is_same<
get_lowest_layer<F1>::type, F1>::value, "");
static_assert(std::is_same<
get_lowest_layer<F2>::type, F2>::value, "");
static_assert(std::is_same<
get_lowest_layer<F3<F1>>::type, F1>::value, "");
static_assert(std::is_same<
get_lowest_layer<F3<F2>>::type, F2>::value, "");
static_assert(std::is_same<
get_lowest_layer<F4<F1>>::type, F1>::value, "");
static_assert(std::is_same<
get_lowest_layer<F4<F2>>::type, F2>::value, "");
static_assert(std::is_same<
get_lowest_layer<F4<F3<F1>>>::type, F1>::value, "");
static_assert(std::is_same<
get_lowest_layer<F4<F3<F2>>>::type, F2>::value, "");
pass();
}
};
BEAST_DEFINE_TESTSUITE(get_lowest_layer,core,beast);
} // detail
} // beast

View File

@@ -0,0 +1,49 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/handler_alloc.hpp>
#include <beast/unit_test/suite.hpp>
#include <vector>
namespace beast {
class handler_alloc_test : public beast::unit_test::suite
{
public:
struct handler
{
void
operator()() const
{
}
};
void
run() override
{
handler h;
handler h2;
handler_alloc<char, handler> a1{h};
handler_alloc<char, handler> a2{h2};
BEAST_EXPECT(a2 == a1);
auto a3 = a1;
BEAST_EXPECT(a3 == a1);
{
std::vector<char,
handler_alloc<char, handler>> v(a1);
v.reserve(32);
v.resize(10);
}
}
};
BEAST_DEFINE_TESTSUITE(handler_alloc,core,beast);
} // beast

View File

@@ -0,0 +1,23 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/handler_concepts.hpp>
namespace beast {
namespace {
struct T
{
void operator()(int);
};
}
static_assert(is_CompletionHandler<T, void(int)>::value, "");
static_assert(! is_CompletionHandler<T, void(void)>::value, "");
} // beast

80
test/core/handler_ptr.cpp Normal file
View File

@@ -0,0 +1,80 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/handler_ptr.hpp>
#include <beast/unit_test/suite.hpp>
#include <exception>
#include <utility>
namespace beast {
class handler_ptr_test : public beast::unit_test::suite
{
public:
struct handler
{
handler() = default;
handler(handler const&) = default;
void
operator()(bool& b) const
{
b = true;
}
};
struct T
{
T(handler&)
{
}
~T()
{
}
};
struct U
{
U(handler&)
{
throw std::exception{};
}
};
void
run() override
{
handler h;
handler_ptr<T, handler> p1{h};
handler_ptr<T, handler> p2{p1};
try
{
handler_ptr<U, handler> p3{h};
fail();
}
catch(std::exception const&)
{
pass();
}
catch(...)
{
fail();
}
handler_ptr<T, handler> p4{std::move(h)};
bool b = false;
p4.invoke(std::ref(b));
BEAST_EXPECT(b);
}
};
BEAST_DEFINE_TESTSUITE(handler_ptr,core,beast);
} // beast

View File

@@ -0,0 +1,56 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/detail/is_call_possible.hpp>
namespace beast {
namespace detail {
namespace {
struct is_call_possible_udt1
{
void operator()(int) const;
};
struct is_call_possible_udt2
{
int operator()(int) const;
};
struct is_call_possible_udt3
{
int operator()(int);
};
#ifndef __INTELLISENSE__
// VFALCO Fails to compile with Intellisense
static_assert(is_call_possible<
is_call_possible_udt1, void(int)>::value, "");
static_assert(! is_call_possible<
is_call_possible_udt1, void(void)>::value, "");
static_assert(is_call_possible<
is_call_possible_udt2, int(int)>::value, "");
static_assert(! is_call_possible<
is_call_possible_udt2, int(void)>::value, "");
static_assert(! is_call_possible<
is_call_possible_udt2, void(void)>::value, "");
static_assert(is_call_possible<
is_call_possible_udt3, int(int)>::value, "");
static_assert(! is_call_possible<
is_call_possible_udt3 const, int(int)>::value, "");
#endif
}
} // detail
} // beast

View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/placeholders.hpp>

View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/prepare_buffer.hpp>

View File

@@ -0,0 +1,177 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/prepare_buffers.hpp>
#include <beast/core/consuming_buffers.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <string>
namespace beast {
class prepare_buffers_test : public beast::unit_test::suite
{
public:
template<class ConstBufferSequence>
static
std::size_t
bsize1(ConstBufferSequence const& bs)
{
using boost::asio::buffer_size;
std::size_t n = 0;
for(auto it = bs.begin(); it != bs.end(); ++it)
n += buffer_size(*it);
return n;
}
template<class ConstBufferSequence>
static
std::size_t
bsize2(ConstBufferSequence const& bs)
{
using boost::asio::buffer_size;
std::size_t n = 0;
for(auto it = bs.begin(); it != bs.end(); it++)
n += buffer_size(*it);
return n;
}
template<class ConstBufferSequence>
static
std::size_t
bsize3(ConstBufferSequence const& bs)
{
using boost::asio::buffer_size;
std::size_t n = 0;
for(auto it = bs.end(); it != bs.begin();)
n += buffer_size(*--it);
return n;
}
template<class ConstBufferSequence>
static
std::size_t
bsize4(ConstBufferSequence const& bs)
{
using boost::asio::buffer_size;
std::size_t n = 0;
for(auto it = bs.end(); it != bs.begin();)
{
it--;
n += buffer_size(*it);
}
return n;
}
template<class ConstBufferSequence>
static
std::string
to_string(ConstBufferSequence const& bs)
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
std::string s;
s.reserve(buffer_size(bs));
for(auto const& b : bs)
s.append(buffer_cast<char const*>(b),
buffer_size(b));
return s;
}
template<class BufferType>
void testMatrix()
{
using boost::asio::buffer_size;
std::string s = "Hello, world";
BEAST_EXPECT(s.size() == 12);
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
std::size_t z = s.size() - (x + y);
{
std::array<BufferType, 3> bs{{
BufferType{&s[0], x},
BufferType{&s[x], y},
BufferType{&s[x+y], z}}};
for(std::size_t i = 0; i <= s.size() + 1; ++i)
{
auto pb = prepare_buffers(i, bs);
BEAST_EXPECT(to_string(pb) == s.substr(0, i));
auto pb2 = pb;
BEAST_EXPECT(to_string(pb2) == to_string(pb));
pb = prepare_buffers(0, bs);
pb2 = pb;
BEAST_EXPECT(buffer_size(pb2) == 0);
pb2 = prepare_buffers(i, bs);
BEAST_EXPECT(to_string(pb2) == s.substr(0, i));
}
}
}}
}
void testNullBuffers()
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
using boost::asio::null_buffers;
auto pb0 = prepare_buffers(0, null_buffers{});
BEAST_EXPECT(buffer_size(pb0) == 0);
auto pb1 = prepare_buffers(1, null_buffers{});
BEAST_EXPECT(buffer_size(pb1) == 0);
BEAST_EXPECT(buffer_copy(pb0, pb1) == 0);
using pb_type = decltype(pb0);
consuming_buffers<pb_type> cb(pb0);
BEAST_EXPECT(buffer_size(cb) == 0);
BEAST_EXPECT(buffer_copy(cb, pb1) == 0);
cb.consume(1);
BEAST_EXPECT(buffer_size(cb) == 0);
BEAST_EXPECT(buffer_copy(cb, pb1) == 0);
auto pbc = prepare_buffers(2, cb);
BEAST_EXPECT(buffer_size(pbc) == 0);
BEAST_EXPECT(buffer_copy(pbc, cb) == 0);
}
void testIterator()
{
using boost::asio::buffer_size;
using boost::asio::const_buffer;
char b[3];
std::array<const_buffer, 3> bs{{
const_buffer{&b[0], 1},
const_buffer{&b[1], 1},
const_buffer{&b[2], 1}}};
auto pb = prepare_buffers(2, bs);
BEAST_EXPECT(bsize1(pb) == 2);
BEAST_EXPECT(bsize2(pb) == 2);
BEAST_EXPECT(bsize3(pb) == 2);
BEAST_EXPECT(bsize4(pb) == 2);
std::size_t n = 0;
for(auto it = pb.end(); it != pb.begin(); --it)
{
decltype(pb)::const_iterator it2(std::move(it));
BEAST_EXPECT(buffer_size(*it2) == 1);
it = std::move(it2);
++n;
}
BEAST_EXPECT(n == 2);
}
void run() override
{
testMatrix<boost::asio::const_buffer>();
testMatrix<boost::asio::mutable_buffer>();
testNullBuffers();
testIterator();
}
};
BEAST_DEFINE_TESTSUITE(prepare_buffers,core,beast);
} // beast

80
test/core/sha1.cpp Normal file
View File

@@ -0,0 +1,80 @@
//
// Copyright (c) 2013-2017 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)
//
#include <beast/core/detail/sha1.hpp>
#include <beast/unit_test/suite.hpp>
#include <array>
namespace beast {
namespace detail {
class sha1_test : public beast::unit_test::suite
{
public:
static
inline
std::uint8_t
unhex(char c)
{
if(c >= '0' && c <= '9')
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
throw std::invalid_argument("not a hex digit");
}
static
std::string
unhex(std::string const& in)
{
std::string out;
out.reserve(in.size() / 2);
if(in.size() % 2)
throw std::domain_error("invalid hex string");
for(std::size_t i = 0; i < in.size(); i += 2)
out.push_back(
(unhex(in[i])<<4) + unhex(in[i+1]));
return out;
}
void
check(std::string const& message, std::string const& answer)
{
std::string digest;
digest = unhex(answer);
sha1_context ctx;
std::string result;
result.resize(sha1_context::digest_size);
init(ctx);
update(ctx, message.data(), message.size());
finish(ctx, &result[0]);
BEAST_EXPECT(result == digest);
}
void
run()
{
// http://www.di-mgt.com.au/sha_testvectors.html
//
check("abc",
"a9993e36" "4706816a" "ba3e2571" "7850c26c" "9cd0d89d");
check("",
"da39a3ee" "5e6b4b0d" "3255bfef" "95601890" "afd80709");
check("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"84983e44" "1c3bd26e" "baae4aa1" "f95129e5" "e54670f1");
check("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
"a49b2446" "a02c645b" "f419f995" "b6709125" "3a04a259");
}
};
BEAST_DEFINE_TESTSUITE(sha1,core,beast);
} // test
} // beast

View File

@@ -0,0 +1,206 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/static_streambuf.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <string>
namespace beast {
class static_streambuf_test : public beast::unit_test::suite
{
public:
template<class ConstBufferSequence>
static
std::string
to_string(ConstBufferSequence const& bs)
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
std::string s;
s.reserve(buffer_size(bs));
for(auto const& b : bs)
s.append(buffer_cast<char const*>(b),
buffer_size(b));
return s;
}
void testStaticStreambuf()
{
using boost::asio::buffer;
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
char buf[12];
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == sizeof(buf));
for(std::size_t i = 1; i < 4; ++i) {
for(std::size_t j = 1; j < 4; ++j) {
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
for(std::size_t t = 1; t < 4; ++ t) {
for(std::size_t u = 1; u < 4; ++ u) {
std::size_t z = sizeof(buf) - (x + y);
std::size_t v = sizeof(buf) - (t + u);
{
std::memset(buf, 0, sizeof(buf));
static_streambuf_n<sizeof(buf)> ba;
{
auto d = ba.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
ba.commit(buffer_copy(d, buffer(s.data(), x)));
}
BEAST_EXPECT(ba.size() == x);
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
}
ba.commit(1);
BEAST_EXPECT(ba.size() == x + y);
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
}
ba.commit(2);
BEAST_EXPECT(ba.size() == x + y + z);
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
BEAST_EXPECT(to_string(ba.data()) == s);
ba.consume(t);
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
BEAST_EXPECT(to_string(ba.data()) == s.substr(t, std::string::npos));
ba.consume(u);
BEAST_EXPECT(to_string(ba.data()) == s.substr(t + u, std::string::npos));
ba.consume(v);
BEAST_EXPECT(to_string(ba.data()) == "");
ba.consume(1);
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
try
{
ba.prepare(1);
fail();
}
catch(...)
{
pass();
}
}
}}}}}}
}
void testIterators()
{
static_streambuf_n<2> ba;
{
auto mb = ba.prepare(2);
std::size_t n;
n = 0;
for(auto it = mb.begin();
it != mb.end(); it++)
++n;
BEAST_EXPECT(n == 1);
mb = ba.prepare(2);
n = 0;
for(auto it = mb.begin();
it != mb.end(); ++it)
++n;
BEAST_EXPECT(n == 1);
mb = ba.prepare(2);
n = 0;
for(auto it = mb.end();
it != mb.begin(); it--)
++n;
BEAST_EXPECT(n == 1);
mb = ba.prepare(2);
n = 0;
for(auto it = mb.end();
it != mb.begin(); --it)
++n;
BEAST_EXPECT(n == 1);
}
ba.prepare(2);
ba.commit(1);
std::size_t n;
n = 0;
for(auto it = ba.data().begin();
it != ba.data().end(); it++)
++n;
BEAST_EXPECT(n == 1);
n = 0;
for(auto it = ba.data().begin();
it != ba.data().end(); ++it)
++n;
BEAST_EXPECT(n == 1);
n = 0;
for(auto it = ba.data().end();
it != ba.data().begin(); it--)
++n;
BEAST_EXPECT(n == 1);
n = 0;
for(auto it = ba.data().end();
it != ba.data().begin(); --it)
++n;
BEAST_EXPECT(n == 1);
}
void run() override
{
testStaticStreambuf();
testIterators();
}
};
BEAST_DEFINE_TESTSUITE(static_streambuf,core,beast);
} // beastp

263
test/core/static_string.cpp Normal file
View File

@@ -0,0 +1,263 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/static_string.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
class static_string_test : public beast::unit_test::suite
{
public:
void testMembers()
{
using str1 = static_string<1>;
using str2 = static_string<2>;
{
str1 s1;
BEAST_EXPECT(s1 == "");
BEAST_EXPECT(s1.empty());
BEAST_EXPECT(s1.size() == 0);
BEAST_EXPECT(s1.max_size() == 1);
BEAST_EXPECT(s1.capacity() == 1);
BEAST_EXPECT(s1.begin() == s1.end());
BEAST_EXPECT(s1.cbegin() == s1.cend());
BEAST_EXPECT(s1.rbegin() == s1.rend());
BEAST_EXPECT(s1.crbegin() == s1.crend());
try
{
BEAST_EXPECT(s1.at(0) == 0);
fail();
}
catch(std::exception const&)
{
pass();
}
BEAST_EXPECT(s1.data()[0] == 0);
BEAST_EXPECT(*s1.c_str() == 0);
BEAST_EXPECT(std::distance(s1.begin(), s1.end()) == 0);
BEAST_EXPECT(std::distance(s1.cbegin(), s1.cend()) == 0);
BEAST_EXPECT(std::distance(s1.rbegin(), s1.rend()) == 0);
BEAST_EXPECT(std::distance(s1.crbegin(), s1.crend()) == 0);
BEAST_EXPECT(s1.compare(s1) == 0);
BEAST_EXPECT(s1.to_string() == std::string{});
}
{
str1 const s1;
BEAST_EXPECT(s1 == "");
BEAST_EXPECT(s1.empty());
BEAST_EXPECT(s1.size() == 0);
BEAST_EXPECT(s1.max_size() == 1);
BEAST_EXPECT(s1.capacity() == 1);
BEAST_EXPECT(s1.begin() == s1.end());
BEAST_EXPECT(s1.cbegin() == s1.cend());
BEAST_EXPECT(s1.rbegin() == s1.rend());
BEAST_EXPECT(s1.crbegin() == s1.crend());
try
{
BEAST_EXPECT(s1.at(0) == 0);
fail();
}
catch(std::exception const&)
{
pass();
}
BEAST_EXPECT(s1.data()[0] == 0);
BEAST_EXPECT(*s1.c_str() == 0);
BEAST_EXPECT(std::distance(s1.begin(), s1.end()) == 0);
BEAST_EXPECT(std::distance(s1.cbegin(), s1.cend()) == 0);
BEAST_EXPECT(std::distance(s1.rbegin(), s1.rend()) == 0);
BEAST_EXPECT(std::distance(s1.crbegin(), s1.crend()) == 0);
BEAST_EXPECT(s1.compare(s1) == 0);
BEAST_EXPECT(s1.to_string() == std::string{});
}
{
str1 s1;
str1 s2("x");
BEAST_EXPECT(s2 == "x");
BEAST_EXPECT(s2[0] == 'x');
BEAST_EXPECT(s2.at(0) == 'x');
BEAST_EXPECT(s2.front() == 'x');
BEAST_EXPECT(s2.back() == 'x');
str1 const s3(s2);
BEAST_EXPECT(s3 == "x");
BEAST_EXPECT(s3[0] == 'x');
BEAST_EXPECT(s3.at(0) == 'x');
BEAST_EXPECT(s3.front() == 'x');
BEAST_EXPECT(s3.back() == 'x');
s2 = "y";
BEAST_EXPECT(s2 == "y");
BEAST_EXPECT(s3 == "x");
s1 = s2;
BEAST_EXPECT(s1 == "y");
s1.clear();
BEAST_EXPECT(s1.empty());
BEAST_EXPECT(s1.size() == 0);
}
{
str2 s1("x");
str1 s2(s1);
BEAST_EXPECT(s2 == "x");
str1 s3;
s3 = s2;
BEAST_EXPECT(s3 == "x");
s1 = "xy";
BEAST_EXPECT(s1.size() == 2);
BEAST_EXPECT(s1[0] == 'x');
BEAST_EXPECT(s1[1] == 'y');
BEAST_EXPECT(s1.at(0) == 'x');
BEAST_EXPECT(s1.at(1) == 'y');
BEAST_EXPECT(s1.front() == 'x');
BEAST_EXPECT(s1.back() == 'y');
auto const s4 = s1;
BEAST_EXPECT(s4[0] == 'x');
BEAST_EXPECT(s4[1] == 'y');
BEAST_EXPECT(s4.at(0) == 'x');
BEAST_EXPECT(s4.at(1) == 'y');
BEAST_EXPECT(s4.front() == 'x');
BEAST_EXPECT(s4.back() == 'y');
try
{
s3 = s1;
fail();
}
catch(std::exception const&)
{
pass();
}
try
{
str1 s5(s1);
fail();
}
catch(std::exception const&)
{
pass();
}
}
{
str1 s1("x");
str2 s2;
s2 = s1;
try
{
s1.resize(2);
fail();
}
catch(std::length_error const&)
{
pass();
}
}
pass();
}
void testCompare()
{
using str1 = static_string<1>;
using str2 = static_string<2>;
{
str1 s1;
str2 s2;
s1 = "1";
s2 = "22";
BEAST_EXPECT(s1.compare(s2) < 0);
BEAST_EXPECT(s2.compare(s1) > 0);
BEAST_EXPECT(s1 < "10");
BEAST_EXPECT(s2 > "1");
BEAST_EXPECT("10" > s1);
BEAST_EXPECT("1" < s2);
BEAST_EXPECT(s1 < "20");
BEAST_EXPECT(s2 > "1");
BEAST_EXPECT(s2 > "2");
}
{
str2 s1("x");
str2 s2("x");
BEAST_EXPECT(s1 == s2);
BEAST_EXPECT(s1 <= s2);
BEAST_EXPECT(s1 >= s2);
BEAST_EXPECT(! (s1 < s2));
BEAST_EXPECT(! (s1 > s2));
BEAST_EXPECT(! (s1 != s2));
}
{
str1 s1("x");
str2 s2("x");
BEAST_EXPECT(s1 == s2);
BEAST_EXPECT(s1 <= s2);
BEAST_EXPECT(s1 >= s2);
BEAST_EXPECT(! (s1 < s2));
BEAST_EXPECT(! (s1 > s2));
BEAST_EXPECT(! (s1 != s2));
}
{
str2 s("x");
BEAST_EXPECT(s == "x");
BEAST_EXPECT(s <= "x");
BEAST_EXPECT(s >= "x");
BEAST_EXPECT(! (s < "x"));
BEAST_EXPECT(! (s > "x"));
BEAST_EXPECT(! (s != "x"));
BEAST_EXPECT("x" == s);
BEAST_EXPECT("x" <= s);
BEAST_EXPECT("x" >= s);
BEAST_EXPECT(! ("x" < s));
BEAST_EXPECT(! ("x" > s));
BEAST_EXPECT(! ("x" != s));
}
{
str2 s("x");
BEAST_EXPECT(s <= "y");
BEAST_EXPECT(s < "y");
BEAST_EXPECT(s != "y");
BEAST_EXPECT(! (s == "y"));
BEAST_EXPECT(! (s >= "y"));
BEAST_EXPECT(! (s > "x"));
BEAST_EXPECT("y" >= s);
BEAST_EXPECT("y" > s);
BEAST_EXPECT("y" != s);
BEAST_EXPECT(! ("y" == s));
BEAST_EXPECT(! ("y" <= s));
BEAST_EXPECT(! ("y" < s));
}
{
str1 s1("x");
str2 s2("y");
BEAST_EXPECT(s1 <= s2);
BEAST_EXPECT(s1 < s2);
BEAST_EXPECT(s1 != s2);
BEAST_EXPECT(! (s1 == s2));
BEAST_EXPECT(! (s1 >= s2));
BEAST_EXPECT(! (s1 > s2));
}
{
str1 s1("x");
str2 s2("xx");
BEAST_EXPECT(s1 < s2);
BEAST_EXPECT(s2 > s1);
}
{
str1 s1("x");
str2 s2("yy");
BEAST_EXPECT(s1 < s2);
BEAST_EXPECT(s2 > s1);
}
}
void run() override
{
testMembers();
testCompare();
}
};
BEAST_DEFINE_TESTSUITE(static_string,core,beast);
} // beast

View File

@@ -0,0 +1,30 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/stream_concepts.hpp>
#include <boost/asio/ip/tcp.hpp>
namespace beast {
using stream_type = boost::asio::ip::tcp::socket;
static_assert(has_get_io_service<stream_type>::value, "");
static_assert(is_AsyncReadStream<stream_type>::value, "");
static_assert(is_AsyncWriteStream<stream_type>::value, "");
static_assert(is_AsyncStream<stream_type>::value, "");
static_assert(is_SyncReadStream<stream_type>::value, "");
static_assert(is_SyncWriteStream<stream_type>::value, "");
static_assert(is_SyncStream<stream_type>::value, "");
static_assert(! has_get_io_service<int>::value, "");
static_assert(! is_AsyncReadStream<int>::value, "");
static_assert(! is_AsyncWriteStream<int>::value, "");
static_assert(! is_SyncReadStream<int>::value, "");
static_assert(! is_SyncWriteStream<int>::value, "");
} // beast

482
test/core/streambuf.cpp Normal file
View File

@@ -0,0 +1,482 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/streambuf.hpp>
#include "buffer_test.hpp"
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/to_string.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <atomic>
#include <memory>
#include <string>
namespace beast {
static_assert(is_DynamicBuffer<streambuf>::value, "");
struct test_allocator_info
{
std::size_t ncopy = 0;
std::size_t nmove = 0;
std::size_t nselect = 0;
};
template<class T,
bool Assign, bool Move, bool Swap, bool Select>
class test_allocator;
template<class T,
bool Assign, bool Move, bool Swap, bool Select>
struct test_allocator_base
{
};
template<class T,
bool Assign, bool Move, bool Swap>
struct test_allocator_base<T, Assign, Move, Swap, true>
{
static
test_allocator<T, Assign, Move, Swap, true>
select_on_container_copy_construction(
test_allocator<T, Assign, Move, Swap, true> const& a)
{
return test_allocator<T, Assign, Move, Swap, true>{};
}
};
template<class T,
bool Assign, bool Move, bool Swap, bool Select>
class test_allocator : public test_allocator_base<
T, Assign, Move, Swap, Select>
{
std::size_t id_;
std::shared_ptr<test_allocator_info> info_;
template<class, bool, bool, bool, bool>
friend class test_allocator;
public:
using value_type = T;
using propagate_on_container_copy_assignment =
std::integral_constant<bool, Assign>;
using propagate_on_container_move_assignment =
std::integral_constant<bool, Move>;
using propagate_on_container_swap =
std::integral_constant<bool, Swap>;
template<class U>
struct rebind
{
using other = test_allocator<
U, Assign, Move, Swap, Select>;
};
test_allocator()
: id_([]
{
static std::atomic<
std::size_t> sid(0);
return ++sid;
}())
, info_(std::make_shared<test_allocator_info>())
{
}
test_allocator(test_allocator const& u) noexcept
: id_(u.id_)
, info_(u.info_)
{
++info_->ncopy;
}
template<class U>
test_allocator(test_allocator<
U, Assign, Move, Swap, Select> const& u) noexcept
: id_(u.id_)
, info_(u.info_)
{
++info_->ncopy;
}
test_allocator(test_allocator&& t)
: id_(t.id_)
, info_(t.info_)
{
++info_->nmove;
}
value_type*
allocate(std::size_t n)
{
return static_cast<value_type*>(
::operator new (n*sizeof(value_type)));
}
void
deallocate(value_type* p, std::size_t) noexcept
{
::operator delete(p);
}
std::size_t
id() const
{
return id_;
}
test_allocator_info const*
operator->() const
{
return info_.get();
}
};
class basic_streambuf_test : public beast::unit_test::suite
{
public:
template<class Alloc1, class Alloc2>
static
bool
eq(basic_streambuf<Alloc1> const& sb1,
basic_streambuf<Alloc2> const& sb2)
{
return to_string(sb1.data()) == to_string(sb2.data());
}
template<class ConstBufferSequence>
void
expect_size(std::size_t n, ConstBufferSequence const& buffers)
{
BEAST_EXPECT(test::size_pre(buffers) == n);
BEAST_EXPECT(test::size_post(buffers) == n);
BEAST_EXPECT(test::size_rev_pre(buffers) == n);
BEAST_EXPECT(test::size_rev_post(buffers) == n);
}
template<class U, class V>
static
void
self_assign(U& u, V&& v)
{
u = std::forward<V>(v);
}
void testSpecialMembers()
{
using boost::asio::buffer;
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == 12);
for(std::size_t i = 1; i < 12; ++i) {
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
std::size_t z = s.size() - (x + y);
{
streambuf sb(i);
sb.commit(buffer_copy(sb.prepare(x), buffer(s.data(), x)));
sb.commit(buffer_copy(sb.prepare(y), buffer(s.data()+x, y)));
sb.commit(buffer_copy(sb.prepare(z), buffer(s.data()+x+y, z)));
BEAST_EXPECT(to_string(sb.data()) == s);
{
streambuf sb2(sb);
BEAST_EXPECT(eq(sb, sb2));
}
{
streambuf sb2;
sb2 = sb;
BEAST_EXPECT(eq(sb, sb2));
}
{
streambuf sb2(std::move(sb));
BEAST_EXPECT(to_string(sb2.data()) == s);
expect_size(0, sb.data());
sb = std::move(sb2);
BEAST_EXPECT(to_string(sb.data()) == s);
expect_size(0, sb2.data());
}
self_assign(sb, sb);
BEAST_EXPECT(to_string(sb.data()) == s);
self_assign(sb, std::move(sb));
BEAST_EXPECT(to_string(sb.data()) == s);
}
}}}
try
{
streambuf sb0(0);
fail();
}
catch(std::exception const&)
{
pass();
}
}
void testAllocator()
{
// VFALCO This needs work
{
using alloc_type =
test_allocator<char, false, false, false, false>;
using sb_type = basic_streambuf<alloc_type>;
sb_type sb;
BEAST_EXPECT(sb.get_allocator().id() == 1);
}
{
using alloc_type =
test_allocator<char, false, false, false, false>;
using sb_type = basic_streambuf<alloc_type>;
sb_type sb;
BEAST_EXPECT(sb.get_allocator().id() == 2);
sb_type sb2(sb);
BEAST_EXPECT(sb2.get_allocator().id() == 2);
sb_type sb3(sb, alloc_type{});
}
}
void
testPrepare()
{
using boost::asio::buffer_size;
{
streambuf sb(2);
BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5);
BEAST_EXPECT(buffer_size(sb.prepare(8)) == 8);
BEAST_EXPECT(buffer_size(sb.prepare(7)) == 7);
}
{
streambuf sb(2);
sb.prepare(2);
BEAST_EXPECT(test::buffer_count(sb.prepare(5)) == 2);
BEAST_EXPECT(test::buffer_count(sb.prepare(8)) == 3);
BEAST_EXPECT(test::buffer_count(sb.prepare(4)) == 2);
}
}
void testCommit()
{
using boost::asio::buffer_size;
streambuf sb(2);
sb.prepare(2);
sb.prepare(5);
sb.commit(1);
expect_size(1, sb.data());
}
void testConsume()
{
using boost::asio::buffer_size;
streambuf sb(1);
expect_size(5, sb.prepare(5));
sb.commit(3);
expect_size(3, sb.data());
sb.consume(1);
expect_size(2, sb.data());
}
void testMatrix()
{
using boost::asio::buffer;
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == 12);
for(std::size_t i = 1; i < 12; ++i) {
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
for(std::size_t t = 1; t < 4; ++ t) {
for(std::size_t u = 1; u < 4; ++ u) {
std::size_t z = s.size() - (x + y);
std::size_t v = s.size() - (t + u);
{
streambuf sb(i);
{
auto d = sb.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = sb.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = sb.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = sb.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
sb.commit(buffer_copy(d, buffer(s.data(), x)));
}
BEAST_EXPECT(sb.size() == x);
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
{
auto d = sb.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = sb.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = sb.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = sb.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
sb.commit(buffer_copy(d, buffer(s.data()+x, y)));
}
sb.commit(1);
BEAST_EXPECT(sb.size() == x + y);
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
{
auto d = sb.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = sb.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = sb.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = sb.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
sb.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
}
sb.commit(2);
BEAST_EXPECT(sb.size() == x + y + z);
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
BEAST_EXPECT(to_string(sb.data()) == s);
sb.consume(t);
{
auto d = sb.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
BEAST_EXPECT(to_string(sb.data()) == s.substr(t, std::string::npos));
sb.consume(u);
BEAST_EXPECT(to_string(sb.data()) == s.substr(t + u, std::string::npos));
sb.consume(v);
BEAST_EXPECT(to_string(sb.data()) == "");
sb.consume(1);
{
auto d = sb.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
}
}}}}}
}
void testIterators()
{
using boost::asio::buffer_size;
streambuf sb(1);
sb.prepare(1);
sb.commit(1);
sb.prepare(2);
sb.commit(2);
expect_size(3, sb.data());
sb.prepare(1);
expect_size(3, sb.prepare(3));
sb.commit(2);
BEAST_EXPECT(test::buffer_count(sb.data()) == 4);
}
void testOutputStream()
{
streambuf sb;
sb << "x";
BEAST_EXPECT(to_string(sb.data()) == "x");
}
void testCapacity()
{
using boost::asio::buffer_size;
{
streambuf sb{10};
BEAST_EXPECT(sb.alloc_size() == 10);
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
BEAST_EXPECT(read_size_helper(sb, 10) == 10);
BEAST_EXPECT(read_size_helper(sb, 20) == 20);
BEAST_EXPECT(read_size_helper(sb, 1000) == 512);
sb.prepare(3);
sb.commit(3);
BEAST_EXPECT(read_size_helper(sb, 10) == 7);
BEAST_EXPECT(read_size_helper(sb, 1000) == 7);
}
{
streambuf sb(1000);
BEAST_EXPECT(sb.alloc_size() == 1000);
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
BEAST_EXPECT(read_size_helper(sb, 1000) == 1000);
BEAST_EXPECT(read_size_helper(sb, 2000) == 1000);
sb.prepare(3);
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
BEAST_EXPECT(read_size_helper(sb, 1000) == 1000);
BEAST_EXPECT(read_size_helper(sb, 2000) == 1000);
sb.commit(3);
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
BEAST_EXPECT(read_size_helper(sb, 1000) == 997);
BEAST_EXPECT(read_size_helper(sb, 2000) == 997);
sb.consume(2);
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
BEAST_EXPECT(read_size_helper(sb, 1000) == 997);
BEAST_EXPECT(read_size_helper(sb, 2000) == 997);
}
{
streambuf sb{2};
BEAST_EXPECT(sb.alloc_size() == 2);
BEAST_EXPECT(test::buffer_count(sb.prepare(2)) == 1);
BEAST_EXPECT(test::buffer_count(sb.prepare(3)) == 2);
BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5);
BEAST_EXPECT(read_size_helper(sb, 10) == 6);
}
{
auto avail =
[](streambuf const& sb)
{
return sb.capacity() - sb.size();
};
streambuf sb{100};
BEAST_EXPECT(sb.alloc_size() == 100);
BEAST_EXPECT(avail(sb) == 0);
sb.prepare(100);
BEAST_EXPECT(avail(sb) == 100);
sb.commit(100);
BEAST_EXPECT(avail(sb) == 0);
sb.consume(100);
BEAST_EXPECT(avail(sb) == 0);
sb.alloc_size(200);
BEAST_EXPECT(sb.alloc_size() == 200);
sb.prepare(1);
BEAST_EXPECT(avail(sb) == 200);
}
}
void run() override
{
testSpecialMembers();
testAllocator();
testPrepare();
testCommit();
testConsume();
testMatrix();
testIterators();
testOutputStream();
testCapacity();
}
};
BEAST_DEFINE_TESTSUITE(basic_streambuf,core,beast);
} // beast

28
test/core/to_string.cpp Normal file
View File

@@ -0,0 +1,28 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/to_string.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
namespace beast {
class to_string_test : public beast::unit_test::suite
{
public:
void run()
{
BEAST_EXPECT(to_string(boost::asio::const_buffers_1("x", 1)) == "x");
}
};
BEAST_DEFINE_TESTSUITE(to_string,core,beast);
} // beast

View File

@@ -0,0 +1,36 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/core/write_dynabuf.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
class write_dynabuf_test : public beast::unit_test::suite
{
public:
void run() override
{
streambuf sb;
std::string s;
write(sb, boost::asio::const_buffer{"", 0});
write(sb, boost::asio::mutable_buffer{nullptr, 0});
write(sb, boost::asio::null_buffers{});
write(sb, boost::asio::const_buffers_1{"", 0});
write(sb, boost::asio::mutable_buffers_1{nullptr, 0});
write(sb, s);
write(sb, 23);
pass();
}
};
BEAST_DEFINE_TESTSUITE(write_dynabuf,core,beast);
} // beast

232
test/core/zlib.cpp Normal file
View File

@@ -0,0 +1,232 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/detail/zlib/deflate_stream.hpp>
#include <beast/detail/zlib/inflate_stream.hpp>
#include <beast/unit_test/suite.hpp>
#include <array>
#include <cassert>
#include <memory>
#include <random>
namespace beast {
namespace zlib {
class zlib_test : public beast::unit_test::suite
{
public:
class buffer
{
std::size_t size_ = 0;
std::size_t capacity_ = 0;
std::unique_ptr<std::uint8_t[]> p_;
public:
buffer() = default;
buffer(buffer&&) = default;
buffer& operator=(buffer&&) = default;
explicit
buffer(std::size_t capacity)
{
reserve(capacity);
}
bool
empty() const
{
return size_ == 0;
}
std::size_t
size() const
{
return size_;
}
std::size_t
capacity() const
{
return capacity_;
}
std::uint8_t const*
data() const
{
return p_.get();
}
std::uint8_t*
data()
{
return p_.get();
}
void
reserve(std::size_t capacity)
{
if(capacity != capacity_)
{
p_.reset(new std::uint8_t[capacity]);
capacity_ = capacity;
}
}
void
resize(std::size_t size)
{
assert(size <= capacity_);
size_ = size;
}
};
buffer
make_source1(std::size_t size)
{
std::mt19937 rng;
buffer b(size);
auto p = b.data();
std::size_t n = 0;
static std::string const chars(
"01234567890{}\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
"{{{{{{{{{{}}}}}}}}}} ");
while(n < size)
{
*p++ = chars[rng()%chars.size()];
++n;
}
b.resize(n);
return b;
}
buffer
make_source2(std::size_t size)
{
std::mt19937 rng;
std::array<double, 2> const i{0, 65535};
std::array<double, 2> const w{0, 1};
std::piecewise_linear_distribution<double> d(
i.begin(), i.end(), w.begin());
buffer b(size);
auto p = b.data();
std::size_t n = 0;
while(n < size)
{
if(n == 1)
{
*p++ = rng()%256;
++n;
continue;
}
auto const v = static_cast<std::uint16_t>(d(rng));
*p++ = v>>8;
*p++ = v&0xff;
n += 2;
}
b.resize(n);
return b;
}
void
checkInflate(buffer const& input, buffer const& original)
{
for(std::size_t i = 0; i < input.size(); ++i)
{
buffer output(original.size());
inflate_stream zs;
zs.avail_in = 0;
zs.next_in = 0;
zs.next_out = output.data();
zs.avail_out = output.capacity();
if(i > 0)
{
zs.next_in = (Byte*)input.data();
zs.avail_in = i;
auto result = zs.write(Z_FULL_FLUSH);
expect(result == Z_OK);
}
zs.next_in = (Byte*)input.data() + i;
zs.avail_in = input.size() - i;
auto result = zs.write(Z_FULL_FLUSH);
output.resize(output.capacity() - zs.avail_out);
expect(result == Z_OK);
expect(output.size() == original.size());
expect(std::memcmp(
output.data(), original.data(), original.size()) == 0);
}
}
void testSpecial()
{
{
deflate_stream zs;
}
{
inflate_stream zs;
}
}
void testCompress()
{
static std::size_t constexpr N = 2048;
for(int source = 0; source <= 1; ++source)
{
buffer original;
switch(source)
{
case 0:
original = make_source1(N);
break;
case 1:
original = make_source2(N);
break;
}
for(int level = 0; level <= 9; ++level)
{
for(int strategy = 0; strategy <= 4; ++strategy)
{
for(int wbits = 15; wbits <= 15; ++wbits)
{
deflate_stream zs;
zs.avail_in = 0;
zs.next_in = 0;
expect(deflate_stream::deflateInit2(&zs,
level,
wbits,
4,
strategy) == Z_OK);
buffer output(deflate_stream::deflateBound(&zs, original.size()));
zs.next_in = (Byte*)original.data();
zs.avail_in = original.size();
zs.next_out = output.data();
zs.avail_out = output.capacity();
auto result = zs.deflate(Z_FULL_FLUSH);
expect(result == Z_OK);
output.resize(output.capacity() - zs.avail_out);
checkInflate(output, original);
}
}
}
}
}
void run() override
{
testSpecial();
testCompress();
}
};
BEAST_DEFINE_TESTSUITE(zlib,core,beast);
} // zlib
} // beast

9
test/http.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http.hpp>

52
test/http/CMakeLists.txt Normal file
View File

@@ -0,0 +1,52 @@
# Part of Beast
GroupSources(extras/beast extras)
GroupSources(include/beast beast)
GroupSources(test/http "/")
add_executable (http-tests
${BEAST_INCLUDES}
${EXTRAS_INCLUDES}
message_fuzz.hpp
fail_parser.hpp
../../extras/beast/unit_test/main.cpp
basic_dynabuf_body.cpp
basic_fields.cpp
basic_parser_v1.cpp
concepts.cpp
empty_body.cpp
fields.cpp
header_parser_v1.cpp
message.cpp
parse.cpp
parse_error.cpp
parser_v1.cpp
read.cpp
reason.cpp
rfc7230.cpp
streambuf_body.cpp
string_body.cpp
write.cpp
chunk_encode.cpp
)
if (NOT WIN32)
target_link_libraries(http-tests ${Boost_LIBRARIES} Threads::Threads)
else()
target_link_libraries(http-tests ${Boost_LIBRARIES})
endif()
add_executable (bench-tests
${BEAST_INCLUDES}
${EXTRAS_INCLUDES}
nodejs_parser.hpp
../../extras/beast/unit_test/main.cpp
nodejs_parser.cpp
parser_bench.cpp
)
if (NOT WIN32)
target_link_libraries(bench-tests ${Boost_LIBRARIES} Threads::Threads)
else()
target_link_libraries(bench-tests ${Boost_LIBRARIES})
endif()

View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/basic_dynabuf_body.hpp>

View File

@@ -0,0 +1,96 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/basic_fields.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/lexical_cast.hpp>
namespace beast {
namespace http {
class basic_fields_test : public beast::unit_test::suite
{
public:
template<class Allocator>
using bha = basic_fields<Allocator>;
using bh = basic_fields<std::allocator<char>>;
template<class Allocator>
static
void
fill(std::size_t n, basic_fields<Allocator>& h)
{
for(std::size_t i = 1; i<= n; ++i)
h.insert(boost::lexical_cast<std::string>(i), i);
}
template<class U, class V>
static
void
self_assign(U& u, V&& v)
{
u = std::forward<V>(v);
}
void testHeaders()
{
bh h1;
BEAST_EXPECT(h1.empty());
fill(1, h1);
BEAST_EXPECT(h1.size() == 1);
bh h2;
h2 = h1;
BEAST_EXPECT(h2.size() == 1);
h2.insert("2", "2");
BEAST_EXPECT(std::distance(h2.begin(), h2.end()) == 2);
h1 = std::move(h2);
BEAST_EXPECT(h1.size() == 2);
BEAST_EXPECT(h2.size() == 0);
bh h3(std::move(h1));
BEAST_EXPECT(h3.size() == 2);
BEAST_EXPECT(h1.size() == 0);
self_assign(h3, std::move(h3));
BEAST_EXPECT(h3.size() == 2);
BEAST_EXPECT(h2.erase("Not-Present") == 0);
}
void testRFC2616()
{
bh h;
h.insert("a", "w");
h.insert("a", "x");
h.insert("aa", "y");
h.insert("b", "z");
BEAST_EXPECT(h.count("a") == 2);
}
void testErase()
{
bh h;
h.insert("a", "w");
h.insert("a", "x");
h.insert("aa", "y");
h.insert("b", "z");
BEAST_EXPECT(h.size() == 4);
h.erase("a");
BEAST_EXPECT(h.size() == 2);
}
void run() override
{
testHeaders();
testRFC2616();
}
};
BEAST_DEFINE_TESTSUITE(basic_fields,http,beast);
} // http
} // beast

File diff suppressed because it is too large Load Diff

136
test/http/chunk_encode.cpp Normal file
View File

@@ -0,0 +1,136 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/chunk_encode.hpp>
#include <beast/core/to_string.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace http {
class chunk_encode_test : public beast::unit_test::suite
{
public:
struct final_chunk
{
std::string s;
final_chunk() = default;
explicit
final_chunk(std::string s_)
: s(std::move(s_))
{
}
};
static
void
encode1(std::string& s, final_chunk const& fc)
{
using boost::asio::buffer;
if(! fc.s.empty())
s.append(to_string(chunk_encode(
false, buffer(fc.s.data(), fc.s.size()))));
s.append(to_string(chunk_encode_final()));
}
static
void
encode1(std::string& s, std::string const& piece)
{
using boost::asio::buffer;
s.append(to_string(chunk_encode(
false, buffer(piece.data(), piece.size()))));
}
static
inline
void
encode(std::string&)
{
}
template<class Arg, class... Args>
static
void
encode(std::string& s, Arg const& arg, Args const&... args)
{
encode1(s, arg);
encode(s, args...);
}
template<class... Args>
void
check(std::string const& answer, Args const&... args)
{
std::string s;
encode(s, args...);
BEAST_EXPECT(s == answer);
}
void run() override
{
check(
"0\r\n\r\n"
"0\r\n\r\n",
"", final_chunk{});
check(
"1\r\n"
"*\r\n"
"0\r\n\r\n",
final_chunk("*"));
check(
"2\r\n"
"**\r\n"
"0\r\n\r\n",
final_chunk("**"));
check(
"1\r\n"
"*\r\n"
"1\r\n"
"*\r\n"
"0\r\n\r\n",
"*", final_chunk("*"));
check(
"5\r\n"
"*****\r\n"
"7\r\n"
"*******\r\n"
"0\r\n\r\n",
"*****", final_chunk("*******"));
check(
"1\r\n"
"*\r\n"
"1\r\n"
"*\r\n"
"0\r\n\r\n",
"*", "*", final_chunk{});
check(
"4\r\n"
"****\r\n"
"0\r\n\r\n",
"****", final_chunk{});
BEAST_EXPECT(to_string(chunk_encode(true,
boost::asio::buffer("****", 4))) ==
"4\r\n****\r\n0\r\n\r\n");
}
};
BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast);
} // http
} // beast

9
test/http/concepts.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/concepts.hpp>

9
test/http/empty_body.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/empty_body.hpp>

120
test/http/fail_parser.hpp Normal file
View File

@@ -0,0 +1,120 @@
//
// Copyright (c) 2013-2017 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)
//
#ifndef BEAST_HTTP_TEST_FAIL_PARSER_HPP
#define BEAST_HTTP_TEST_FAIL_PARSER_HPP
#include <beast/http/basic_parser_v1.hpp>
#include <beast/test/fail_counter.hpp>
namespace beast {
namespace http {
template<bool isRequest>
class fail_parser
: public basic_parser_v1<isRequest, fail_parser<isRequest>>
{
test::fail_counter& fc_;
std::uint64_t content_length_ = no_content_length;
body_what body_rv_ = body_what::normal;
public:
std::string body;
template<class... Args>
explicit
fail_parser(test::fail_counter& fc, Args&&... args)
: fc_(fc)
{
}
void
on_body_rv(body_what rv)
{
body_rv_ = rv;
}
// valid on successful parse
std::uint64_t
content_length() const
{
return content_length_;
}
void on_start(error_code& ec)
{
fc_.fail(ec);
}
void on_method(boost::string_ref const&, error_code& ec)
{
fc_.fail(ec);
}
void on_uri(boost::string_ref const&, error_code& ec)
{
fc_.fail(ec);
}
void on_reason(boost::string_ref const&, error_code& ec)
{
fc_.fail(ec);
}
void on_request(error_code& ec)
{
fc_.fail(ec);
}
void on_response(error_code& ec)
{
fc_.fail(ec);
}
void on_field(boost::string_ref const&, error_code& ec)
{
fc_.fail(ec);
}
void on_value(boost::string_ref const&, error_code& ec)
{
fc_.fail(ec);
}
void
on_header(std::uint64_t content_length, error_code& ec)
{
if(fc_.fail(ec))
return;
}
body_what
on_body_what(std::uint64_t content_length, error_code& ec)
{
if(fc_.fail(ec))
return body_what::normal;
content_length_ = content_length;
return body_rv_;
}
void on_body(boost::string_ref const& s, error_code& ec)
{
if(fc_.fail(ec))
return;
body.append(s.data(), s.size());
}
void on_complete(error_code& ec)
{
fc_.fail(ec);
}
};
} // http
} // beast
#endif

9
test/http/fields.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/fields.hpp>

View File

@@ -0,0 +1,90 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/header_parser_v1.hpp>
#include <beast/http/fields.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
namespace beast {
namespace http {
class header_parser_v1_test : public beast::unit_test::suite
{
public:
void testParser()
{
{
error_code ec;
header_parser_v1<true, fields> p;
BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer(
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"\r\n"
), ec);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(p.complete());
BEAST_EXPECT(n == 36);
}
{
error_code ec;
header_parser_v1<true, fields> p;
BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer(
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"
), ec);
BEAST_EXPECT(n == 55);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(p.complete());
}
{
error_code ec;
header_parser_v1<false, fields> p;
BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer(
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"\r\n"
), ec);
BEAST_EXPECT(n == 33);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(p.complete());
}
{
error_code ec;
header_parser_v1<false, fields> p;
BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer(
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"
), ec);
BEAST_EXPECT(n == 52);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(p.complete());
}
}
void run() override
{
testParser();
}
};
BEAST_DEFINE_TESTSUITE(header_parser_v1,http,beast);
} // http
} // beast

308
test/http/message.cpp Normal file
View File

@@ -0,0 +1,308 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/message.hpp>
#include <beast/http/empty_body.hpp>
#include <beast/http/fields.hpp>
#include <beast/http/string_body.hpp>
#include <beast/unit_test/suite.hpp>
#include <type_traits>
namespace beast {
namespace http {
class message_test : public beast::unit_test::suite
{
public:
struct Arg1
{
bool moved = false;
Arg1() = default;
Arg1(Arg1&& other)
{
other.moved = true;
}
};
struct Arg2 { };
struct Arg3 { };
// default constructible Body
struct default_body
{
using value_type = std::string;
};
// 1-arg constructible Body
struct one_arg_body
{
struct value_type
{
explicit
value_type(Arg1 const&)
{
}
explicit
value_type(Arg1&& arg)
{
Arg1 arg_(std::move(arg));
}
};
};
// 2-arg constructible Body
struct two_arg_body
{
struct value_type
{
value_type(Arg1 const&, Arg2 const&)
{
}
};
};
void testMessage()
{
static_assert(std::is_constructible<
message<true, default_body, fields>>::value, "");
static_assert(std::is_constructible<
message<true, one_arg_body, fields>, Arg1>::value, "");
static_assert(std::is_constructible<
message<true, one_arg_body, fields>, Arg1 const>::value, "");
static_assert(std::is_constructible<
message<true, one_arg_body, fields>, Arg1 const&>::value, "");
static_assert(std::is_constructible<
message<true, one_arg_body, fields>, Arg1&&>::value, "");
static_assert(! std::is_constructible<
message<true, one_arg_body, fields>>::value, "");
static_assert(std::is_constructible<
message<true, one_arg_body, fields>,
Arg1, fields::allocator_type>::value, "");
static_assert(std::is_constructible<
message<true, one_arg_body, fields>, std::piecewise_construct_t,
std::tuple<Arg1>>::value, "");
static_assert(std::is_constructible<
message<true, two_arg_body, fields>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>>::value, "");
static_assert(std::is_constructible<
message<true, two_arg_body, fields>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>, std::tuple<fields::allocator_type>>::value, "");
{
Arg1 arg1;
message<true, one_arg_body, fields>{std::move(arg1)};
BEAST_EXPECT(arg1.moved);
}
{
fields h;
h.insert("User-Agent", "test");
message<true, one_arg_body, fields> m{Arg1{}, h};
BEAST_EXPECT(h["User-Agent"] == "test");
BEAST_EXPECT(m.fields["User-Agent"] == "test");
}
{
fields h;
h.insert("User-Agent", "test");
message<true, one_arg_body, fields> m{Arg1{}, std::move(h)};
BEAST_EXPECT(! h.exists("User-Agent"));
BEAST_EXPECT(m.fields["User-Agent"] == "test");
}
// swap
message<true, string_body, fields> m1;
message<true, string_body, fields> m2;
m1.url = "u";
m1.body = "1";
m1.fields.insert("h", "v");
m2.method = "G";
m2.body = "2";
swap(m1, m2);
BEAST_EXPECT(m1.method == "G");
BEAST_EXPECT(m2.method.empty());
BEAST_EXPECT(m1.url.empty());
BEAST_EXPECT(m2.url == "u");
BEAST_EXPECT(m1.body == "2");
BEAST_EXPECT(m2.body == "1");
BEAST_EXPECT(! m1.fields.exists("h"));
BEAST_EXPECT(m2.fields.exists("h"));
}
struct MoveHeaders
{
bool moved_to = false;
bool moved_from = false;
MoveHeaders() = default;
MoveHeaders(MoveHeaders&& other)
: moved_to(true)
{
other.moved_from = true;
}
MoveHeaders& operator=(MoveHeaders&& other)
{
return *this;
}
};
void testHeaders()
{
{
using req_type = request_header;
static_assert(std::is_copy_constructible<req_type>::value, "");
static_assert(std::is_move_constructible<req_type>::value, "");
static_assert(std::is_copy_assignable<req_type>::value, "");
static_assert(std::is_move_assignable<req_type>::value, "");
using res_type = response_header;
static_assert(std::is_copy_constructible<res_type>::value, "");
static_assert(std::is_move_constructible<res_type>::value, "");
static_assert(std::is_copy_assignable<res_type>::value, "");
static_assert(std::is_move_assignable<res_type>::value, "");
}
{
MoveHeaders h;
header<true, MoveHeaders> r{std::move(h)};
BEAST_EXPECT(h.moved_from);
BEAST_EXPECT(r.fields.moved_to);
request<string_body, MoveHeaders> m{std::move(r)};
BEAST_EXPECT(r.fields.moved_from);
BEAST_EXPECT(m.fields.moved_to);
}
}
void testFreeFunctions()
{
{
request<empty_body> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.fields.insert("Upgrade", "test");
BEAST_EXPECT(! is_upgrade(m));
prepare(m, connection::upgrade);
BEAST_EXPECT(is_upgrade(m));
BEAST_EXPECT(m.fields["Connection"] == "upgrade");
m.version = 10;
BEAST_EXPECT(! is_upgrade(m));
}
}
void testPrepare()
{
request<empty_body> m;
m.version = 10;
BEAST_EXPECT(! is_upgrade(m));
m.fields.insert("Transfer-Encoding", "chunked");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
}
m.fields.erase("Transfer-Encoding");
m.fields.insert("Content-Length", "0");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
pass();
}
m.fields.erase("Content-Length");
m.fields.insert("Connection", "keep-alive");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
pass();
}
m.version = 11;
m.fields.erase("Connection");
m.fields.insert("Connection", "close");
BEAST_EXPECT(! is_keep_alive(m));
}
void testSwap()
{
message<false, string_body, fields> m1;
message<false, string_body, fields> m2;
m1.status = 200;
m1.version = 10;
m1.body = "1";
m1.fields.insert("h", "v");
m2.status = 404;
m2.reason = "OK";
m2.body = "2";
m2.version = 11;
swap(m1, m2);
BEAST_EXPECT(m1.status == 404);
BEAST_EXPECT(m2.status == 200);
BEAST_EXPECT(m1.reason == "OK");
BEAST_EXPECT(m2.reason.empty());
BEAST_EXPECT(m1.version == 11);
BEAST_EXPECT(m2.version == 10);
BEAST_EXPECT(m1.body == "2");
BEAST_EXPECT(m2.body == "1");
BEAST_EXPECT(! m1.fields.exists("h"));
BEAST_EXPECT(m2.fields.exists("h"));
}
void
testSpecialMembers()
{
response<string_body> r1;
response<string_body> r2{r1};
response<string_body> r3{std::move(r2)};
r2 = r3;
r1 = std::move(r2);
[r1]()
{
}();
}
void run() override
{
testMessage();
testHeaders();
testFreeFunctions();
testPrepare();
testSwap();
testSpecialMembers();
}
};
BEAST_DEFINE_TESTSUITE(message,http,beast);
} // http
} // beast

563
test/http/message_fuzz.hpp Normal file
View File

@@ -0,0 +1,563 @@
//
// Copyright (c) 2013-2017 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)
//
#ifndef BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
#define BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
#include <beast/core/write_dynabuf.hpp>
#include <beast/http/detail/basic_parser_v1.hpp>
#include <beast/http/detail/rfc7230.hpp>
#include <cstdint>
#include <random>
#include <string>
namespace beast {
namespace http {
template<class = void>
std::string
escaped_string(boost::string_ref const& s)
{
std::string out;
out.reserve(s.size());
char const* p = s.data();
while(p != s.end())
{
if(*p == '\r')
out.append("\\r");
else if(*p == '\n')
out.append("\\n");
else if(*p == '\t')
out.append("\\t");
else
out.append(p, 1);
++p;
}
return out;
}
// Produces random HTTP messages
//
template<class = void>
class message_fuzz_t
{
std::mt19937 rng_;
static
std::string
to_hex(std::size_t v)
{
if(! v)
return "0";
std::string s;
while(v > 0)
{
s.insert(s.begin(),
"0123456789abcdef"[v&0xf]);
v >>= 4;
}
return s;
}
public:
template<class UInt = std::size_t>
UInt
rand(std::size_t n)
{
return static_cast<UInt>(
std::uniform_int_distribution<
std::size_t>{0, n-1}(rng_));
}
std::string
method()
{
#if 0
// All IANA registered methods
static char const* const list[39] = {
"ACL", "BASELINE-CONTROL", "BIND", "CHECKIN", "CHECKOUT", "CONNECT",
"COPY", "DELETE", "GET", "HEAD", "LABEL", "LINK", "LOCK", "MERGE",
"MKACTIVITY", "MKCALENDAR", "MKCOL", "MKREDIRECTREF", "MKWORKSPACE",
"MOVE", "OPTIONS", "ORDERPATCH", "PATCH", "POST", "PRI", "PROPFIND",
"PROPPATCH", "PUT", "REBIND", "REPORT", "SEARCH", "TRACE", "UNBIND",
"UNCHECKOUT", "UNLINK", "UNLOCK", "UPDATE", "UPDATEREDIRECTREF",
"VERSION-CONTROL"
};
return list[rand(39)];
#else
// methods parsed by nodejs-http-parser
static char const* const list[33] = {
"ACL", "BIND", "CHECKOUT", "CONNECT", "COPY", "DELETE", "HEAD", "GET",
"LINK", "LOCK", "MERGE", "MKCOL", "MKCALENDAR", "MKACTIVITY", "M-SEARCH",
"MOVE", "NOTIFY", "OPTIONS", "PATCH", "POST", "PROPFIND", "PROPPATCH",
"PURGE", "PUT", "REBIND", "REPORT", "SEARCH", "SUBSCRIBE", "TRACE",
"UNBIND", "UNLINK", "UNLOCK", "UNSUBSCRIBE"
};
return list[rand(33)];
#endif
}
std::string
scheme()
{
static char const* const list[241] = {
"aaa", "aaas", "about", "acap", "acct", "acr", "adiumxtra", "afp", "afs",
"aim", "appdata", "apt", "attachment", "aw", "barion", "beshare", "bitcoin",
"blob", "bolo", "callto", "cap", "chrome", "chrome-extension", "cid",
"coap", "coaps", "com-eventbrite-attendee", "content", "crid", "cvs",
"data", "dav", "dict", "dis", "dlna-playcontainer", "dlna-playsingle",
"dns", "dntp", "dtn", "dvb", "ed2k", "example", "facetime", "fax", "feed",
"feedready", "file", "filesystem", "finger", "fish", "ftp", "geo", "gg",
"git", "gizmoproject", "go", "gopher", "gtalk", "h323", "ham", "hcp",
"http", "https", "iax", "icap", "icon", "im", "imap", "info", "iotdisco",
"ipn", "ipp", "ipps", "irc", "irc6", "ircs", "iris", "iris.beep",
"iris.lwz", "iris.xpc", "iris.xpcs", "isostore", "itms", "jabber", "jar",
"jms", "keyparc", "lastfm", "ldap", "ldaps", "magnet", "mailserver",
"mailto", "maps", "market", "message", "mid", "mms",
"modem", "ms-access", "ms-drive-to", "ms-enrollment", "ms-excel",
"ms-getoffice", "ms-help", "ms-infopath", "ms-media-stream-id", "ms-project",
"ms-powerpoint", "ms-publisher", "ms-search-repair",
"ms-secondary-screen-controller", "ms-secondary-screen-setup",
"ms-settings", "ms-settings-airplanemode", "ms-settings-bluetooth",
"ms-settings-camera", "ms-settings-cellular", "ms-settings-cloudstorage",
"ms-settings-emailandaccounts", "ms-settings-language", "ms-settings-location",
"ms-settings-lock", "ms-settings-nfctransactions", "ms-settings-notifications",
"ms-settings-power", "ms-settings-privacy", "ms-settings-proximity",
"ms-settings-screenrotation", "ms-settings-wifi", "ms-settings-workplace",
"ms-spd", "ms-transit-to", "ms-visio", "ms-walk-to", "ms-word", "msnim",
"msrp", "msrps", "mtqp", "mumble", "mupdate", "mvn", "news", "nfs", "ni",
"nih", "nntp", "notes", "oid", "opaquelocktoken", "pack", "palm", "paparazzi",
"pkcs11", "platform", "pop", "pres", "prospero", "proxy", "psyc", "query",
"redis", "rediss", "reload", "res", "resource", "rmi", "rsync", "rtmfp",
"rtmp", "rtsp", "rtsps", "rtspu", "secondlife", "service", "session", "sftp",
"sgn", "shttp", "sieve", "sip", "sips", "skype", "smb", "sms", "smtp",
"snews", "snmp", "soap.beep", "soap.beeps", "soldat", "spotify", "ssh",
"steam", "stun", "stuns", "submit", "svn", "tag", "teamspeak", "tel",
"teliaeid", "telnet", "tftp", "things", "thismessage", "tip", "tn3270",
"tool", "turn", "turns", "tv", "udp", "unreal", "urn", "ut2004", "v-event",
"vemmi", "ventrilo", "videotex", "vnc", "view-source", "wais", "webcal",
"wpid", "ws", "wss", "wtai", "wyciwyg", "xcon", "xcon-userid", "xfire",
"xmlrpc.beep", "xmlrpc.beeps", "xmpp", "xri", "ymsgr", "z39.50", "z39.50r",
"z39.50s:"
};
return list[rand(241)];
}
std::string
pchar()
{
if(rand(4))
return std::string(1,
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
":@&=+$,"[rand(69)]);
std::string s = "%";
s += "0123456789abcdef"[rand(16)];
s += "0123456789abcdef"[rand(16)];
return s;
}
char
uric()
{
return 'a';
}
char
uric_no_slash()
{
return 'a';
}
std::string
param()
{
std::string s;
while(rand(2))
s += pchar();
return s;
}
std::string
query()
{
std::string s;
while(rand(2))
s += uric();
return s;
}
std::string
userinfo()
{
std::string s;
while(rand(2))
s += "a";
return s;
}
/* authority = server | reg_name
reg_name = 1*( unreserved | escaped | "$" | "," |
";" | ":" | "@" | "&" | "=" | "+" )
server = [ [ userinfo "@" ] hostport ]
userinfo = *( unreserved | escaped |
";" | ":" | "&" | "=" | "+" | "$" | "," )
hostport = host [ ":" port ]
host = hostname | IPv4address
hostname = *( domainlabel "." ) toplabel [ "." ]
domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
toplabel = alpha | alpha *( alphanum | "-" ) alphanum
IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
port = *digit
*/
std::string
server()
{
std::string s;
if(rand(2))
s += userinfo() + "@";
return s;
}
std::string
reg_name()
{
std::string s;
s = "a";
while(rand(2))
s += "a";
return s;
}
std::string
authority()
{
if(rand(2))
return server();
return reg_name();
}
std::string
opaque_part()
{
std::string s;
s += uric_no_slash();
while(rand(2))
s += uric();
return s;
}
/* abs_path = "/" path_segments
path_segments = segment *( "/" segment )
segment = *pchar *( ";" param )
param = *pchar
pchar = unreserved | escaped |
":" | "@" | "&" | "=" | "+" | "$" | ","
*/
std::string
abs_path()
{
std::string s = "/";
for(;;)
{
while(rand(2))
s += pchar();
while(rand(2))
s += ";" + param();
if(rand(2))
break;
s.append("/");
}
return s;
}
/* net_path = "//" authority [ abs_path ]
*/
std::string
net_path()
{
std::string s = "//";
s += authority();
if(rand(2))
s += abs_path();
return s;
}
/* absoluteURI = scheme ":" ( hier_part | opaque_part )
scheme = alpha *( alpha | digit | "+" | "-" | "." )
hier_part = ( net_path | abs_path ) [ "?" query ]
abs_path = "/" path_segments
query = *uric
opaque_part = uric_no_slash *uric
*/
std::string
abs_uri()
{
std::string s;
s = scheme() + ":";
if(rand(2))
{
if(rand(2))
s += net_path();
else
s += abs_path();
if(rand(2))
s += "?" + query();
}
else
{
s += opaque_part();
}
return s;
}
std::string
uri()
{
//switch(rand(4))
switch(1)
{
case 0: return abs_uri();
case 1: return abs_path();
case 2: return authority();
default:
case 3: break;
}
return "*";
}
std::string
token()
{
static char constexpr valid[78] =
"!#$%&\'*+-." "0123456789" "ABCDEFGHIJ" "KLMNOPQRST"
"UVWXYZ^_`a" "bcdefghijk" "lmnopqrstu" "vwxyz|~";
std::string s;
s.append(1, valid[rand(77)]);
while(rand(4))
s.append(1, valid[rand(77)]);
return s;
}
#if 0
std::string
uri()
{
static char constexpr alpha[63] =
"0123456789" "ABCDEFGHIJ" "KLMNOPQRST"
"UVWXYZabcd" "efghijklmn" "opqrstuvwx" "yz";
std::string s;
s = "/";
while(rand(4))
s.append(1, alpha[rand(62)]);
return s;
}
#endif
std::string
field()
{ static char const* const list[289] =
{
"A-IM",
"Accept", "Accept-Additions", "Accept-Charset", "Accept-Datetime", "Accept-Encoding",
"Accept-Features", "Accept-Language", "Accept-Patch", "Accept-Ranges", "Age", "Allow",
"ALPN", "Also-Control", "Alt-Svc", "Alt-Used", "Alternate-Recipient", "Alternates",
"Apply-To-Redirect-Ref", "Approved", "Archive", "Archived-At", "Article-Names",
"Article-Updates", "Authentication-Info", "Authentication-Results", "Authorization",
"Auto-Submitted", "Autoforwarded", "Autosubmitted", "Base", "Bcc", "Body", "C-Ext",
"C-Man", "C-Opt", "C-PEP", "C-PEP-Info", "Cache-Control",
"CalDAV-Timezones", "Cc", "Close", "Comments", /*"Connection",*/ "Content-Alternative",
"Content-Base", "Content-Description", "Content-Disposition", "Content-Duration",
"Content-Encoding", "Content-features", "Content-ID", "Content-Identifier",
"Content-Language", /*"Content-Length",*/ "Content-Location", "Content-MD5",
"Content-Range", "Content-Return", "Content-Script-Type", "Content-Style-Type",
"Content-Transfer-Encoding", "Content-Type", "Content-Version", "Control", "Conversion",
"Conversion-With-Loss", "Cookie", "Cookie2", "DASL", "DAV", "DL-Expansion-History", "Date",
"Date-Received", "Default-Style", "Deferred-Delivery", "Delivery-Date", "Delta-Base",
"Depth", "Derived-From", "Destination", "Differential-ID", "Digest",
"Discarded-X400-IPMS-Extensions", "Discarded-X400-MTS-Extensions", "Disclose-Recipients",
"Disposition-Notification-Options", "Disposition-Notification-To", "Distribution",
"DKIM-Signature", "Downgraded-Bcc", "Downgraded-Cc", "Downgraded-Disposition-Notification-To",
"Downgraded-Final-Recipient", "Downgraded-From", "Downgraded-In-Reply-To",
"Downgraded-Mail-From", "Downgraded-Message-Id", "Downgraded-Original-Recipient",
"Downgraded-Rcpt-To", "Downgraded-References", "Downgraded-Reply-To", "Downgraded-Resent-Bcc",
"Downgraded-Resent-Cc", "Downgraded-Resent-From", "Downgraded-Resent-Reply-To",
"Downgraded-Resent-Sender", "Downgraded-Resent-To", "Downgraded-Return-Path",
"Downgraded-Sender", "Downgraded-To", "Encoding", "Encrypted", "ETag", "Expect",
"Expires", "Expiry-Date", "Ext", "Followup-To", "Forwarded", "From",
"Generate-Delivery-Report", "GetProfile", "Hobareg", "Host", "HTTP2-Settings", "IM", "If",
"If-Match", "If-Modified-Since", "If-None-Match", "If-Range", "If-Schedule-Tag-Match",
"If-Unmodified-Since", "Importance", "In-Reply-To", "Incomplete-Copy", "Injection-Date",
"Injection-Info", "Keep-Alive", "Keywords", "Label", "Language", "Last-Modified",
"Latest-Delivery-Time", "Lines", "Link", "List-Archive", "List-Help", "List-ID",
"List-Owner", "List-Post", "List-Subscribe", "List-Unsubscribe", "Location", "Lock-Token",
"Man", "Max-Forwards", "Memento-Datetime", "Message-Context", "Message-ID", "Message-Type",
"Meter", "MIME-Version", "MMHS-Exempted-Address", "MMHS-Extended-Authorisation-Info",
"MMHS-Subject-Indicator-Codes", "MMHS-Handling-Instructions", "MMHS-Message-Instructions",
"MMHS-Codress-Message-Indicator", "MMHS-Originator-Reference", "MMHS-Primary-Precedence",
"MMHS-Copy-Precedence", "MMHS-Message-Type", "MMHS-Other-Recipients-Indicator-To",
"MMHS-Other-Recipients-Indicator-CC", "MMHS-Acp127-Message-Identifier", "MMHS-Originator-PLAD",
"MT-Priority", "Negotiate", "Newsgroups", "NNTP-Posting-Date", "NNTP-Posting-Host",
"Obsoletes", "Opt", "Ordering-Type", "Organization", "Origin",
"Original-Encoded-Information-Types", "Original-From", "Original-Message-ID",
"Original-Recipient", "Original-Sender", "Originator-Return-Address", "Original-Subject",
"Overwrite", "P3P", "Path", "PEP", "PICS-Label", "Pep-Info", "Position", "Posting-Version",
"Pragma", "Prefer", "Preference-Applied", "Prevent-NonDelivery-Report", "Priority",
"ProfileObject", "Protocol", "Protocol-Info", "Protocol-Query", "Protocol-Request",
"Proxy-Authenticate", "Proxy-Authentication-Info", "Proxy-Authorization", "Proxy-Features",
"Proxy-Instruction", "Public", "Public-Key-Pins", "Public-Key-Pins-Report-Only", "Range",
"Received", "Received-SPF", "Redirect-Ref", "References", "Referer", "Relay-Version",
"Reply-By", "Reply-To", "Require-Recipient-Valid-Since", "Resent-Bcc", "Resent-Cc",
"Resent-Date", "Resent-From", "Resent-Message-ID", "Resent-Reply-To", "Resent-Sender",
"Resent-To", "Retry-After", "Return-Path", "Safe", "Schedule-Reply", "Schedule-Tag",
"Sec-WebSocket-Accept", "Sec-WebSocket-Extensions", "Sec-WebSocket-Key",
"Sec-WebSocket-Protocol", "Sec-WebSocket-Version", "Security-Scheme", "See-Also", "Sender",
"Sensitivity", "Server", "Set-Cookie", "Set-Cookie2",
"SetProfile", "SLUG", "SoapAction", "Solicitation", "Status-URI", "Strict-Transport-Security",
"Subject", "Summary", "Supersedes", "Surrogate-Capability", "Surrogate-Control", "TCN",
"TE", "Timeout", "To", "Trailer", /*"Transfer-Encoding",*/ "URI", /*"Upgrade",*/ "User-Agent",
"Variant-Vary", "Vary", "VBR-Info", "Via", "WWW-Authenticate", "Want-Digest", "Warning",
"X400-Content-Identifier", "X400-Content-Return", "X400-Content-Type", "X400-MTS-Identifier",
"X400-Originator", "X400-Received", "X400-Recipients", "X400-Trace", "X-Frame-Options", "Xref"
};
return list[rand(289)];
}
std::string
text()
{
std::string s;
while(rand(3))
{
for(;;)
{
char c = rand<char>(256);
if(detail::is_text(c))
{
s.append(1, c);
break;
}
}
}
return s;
}
std::string
value()
{
std::string s;
while(rand(3))
{
if(rand(5))
{
s.append(text());
}
else
{
// LWS
if(! rand(4))
s.append("\r\n");
s.append(1, rand(2) ? ' ' : '\t');
while(rand(2))
s.append(1, rand(2) ? ' ' : '\t');
}
}
return s;
}
template<class DynamicBuffer>
void
fields(DynamicBuffer& db)
{
while(rand(6))
{
write(db, field());
write(db, rand(4) ? ": " : ":");
write(db, value());
write(db, "\r\n");
}
}
template<class DynamicBuffer>
void
body(DynamicBuffer& db)
{
if(! rand(4))
{
write(db, "Content-Length: 0\r\n\r\n");
return;
}
if(rand(2))
{
auto const len = rand(500);
write(db, "Content-Length: ", len, "\r\n\r\n");
for(auto const& b : db.prepare(len))
{
auto p = boost::asio::buffer_cast<char*>(b);
auto n = boost::asio::buffer_size(b);
while(n--)
*p++ = static_cast<char>(32 + rand(26+26+10+6));
}
db.commit(len);
}
else
{
auto len = rand(500);
write(db, "Transfer-Encoding: chunked\r\n\r\n");
while(len > 0)
{
auto n = (std::min)(1 + rand(300), len);
len -= n;
write(db, to_hex(n), "\r\n");
for(auto const& b : db.prepare(n))
{
auto p = boost::asio::buffer_cast<char*>(b);
auto m = boost::asio::buffer_size(b);
while(m--)
*p++ = static_cast<char>(32 + rand(26+26+10+6));
}
db.commit(n);
write(db, "\r\n");
}
write(db, "0\r\n\r\n");
}
}
template<class DynamicBuffer>
void
request(DynamicBuffer& db)
{
write(db, method(), " ", uri(), " HTTP/1.1\r\n");
fields(db);
body(db);
}
template<class DynamicBuffer>
void
response(DynamicBuffer& db)
{
write(db, "HTTP/1.");
write(db, rand(2) ? "0" : "1");
write(db, " ", 100 + rand(401), " ");
write(db, token());
write(db, "\r\n");
fields(db);
body(db);
write(db, "\r\n");
}
};
using message_fuzz = message_fuzz_t<>;
} // http
} // beast
#endif

View File

@@ -0,0 +1,68 @@
# Authors ordered by first contribution.
Ryan Dahl <ry@tinyclouds.org>
Jeremy Hinegardner <jeremy@hinegardner.org>
Sergey Shepelev <temotor@gmail.com>
Joe Damato <ice799@gmail.com>
tomika <tomika_nospam@freemail.hu>
Phoenix Sol <phoenix@burninglabs.com>
Cliff Frey <cliff@meraki.com>
Ewen Cheslack-Postava <ewencp@cs.stanford.edu>
Santiago Gala <sgala@apache.org>
Tim Becker <tim.becker@syngenio.de>
Jeff Terrace <jterrace@gmail.com>
Ben Noordhuis <info@bnoordhuis.nl>
Nathan Rajlich <nathan@tootallnate.net>
Mark Nottingham <mnot@mnot.net>
Aman Gupta <aman@tmm1.net>
Tim Becker <tim.becker@kuriositaet.de>
Sean Cunningham <sean.cunningham@mandiant.com>
Peter Griess <pg@std.in>
Salman Haq <salman.haq@asti-usa.com>
Cliff Frey <clifffrey@gmail.com>
Jon Kolb <jon@b0g.us>
Fouad Mardini <f.mardini@gmail.com>
Paul Querna <pquerna@apache.org>
Felix Geisendörfer <felix@debuggable.com>
koichik <koichik@improvement.jp>
Andre Caron <andre.l.caron@gmail.com>
Ivo Raisr <ivosh@ivosh.net>
James McLaughlin <jamie@lacewing-project.org>
David Gwynne <loki@animata.net>
Thomas LE ROUX <thomas@november-eleven.fr>
Randy Rizun <rrizun@ortivawireless.com>
Andre Louis Caron <andre.louis.caron@usherbrooke.ca>
Simon Zimmermann <simonz05@gmail.com>
Erik Dubbelboer <erik@dubbelboer.com>
Martell Malone <martellmalone@gmail.com>
Bertrand Paquet <bpaquet@octo.com>
BogDan Vatra <bogdan@kde.org>
Peter Faiman <peter@thepicard.org>
Corey Richardson <corey@octayn.net>
Tóth Tamás <tomika_nospam@freemail.hu>
Cam Swords <cam.swords@gmail.com>
Chris Dickinson <christopher.s.dickinson@gmail.com>
Uli Köhler <ukoehler@btronik.de>
Charlie Somerville <charlie@charliesomerville.com>
Patrik Stutz <patrik.stutz@gmail.com>
Fedor Indutny <fedor.indutny@gmail.com>
runner <runner.mei@gmail.com>
Alexis Campailla <alexis@janeasystems.com>
David Wragg <david@wragg.org>
Vinnie Falco <vinnie.falco@gmail.com>
Alex Butum <alexbutum@linux.com>
Rex Feng <rexfeng@gmail.com>
Alex Kocharin <alex@kocharin.ru>
Mark Koopman <markmontymark@yahoo.com>
Helge Heß <me@helgehess.eu>
Alexis La Goutte <alexis.lagoutte@gmail.com>
George Miroshnykov <george.miroshnykov@gmail.com>
Maciej Małecki <me@mmalecki.com>
Marc O'Morain <github.com@marcomorain.com>
Jeff Pinner <jpinner@twitter.com>
Timothy J Fontaine <tjfontaine@gmail.com>
Akagi201 <akagi201@gmail.com>
Romain Giraud <giraud.romain@gmail.com>
Jay Satiro <raysatiro@yahoo.com>
Arne Steen <Arne.Steen@gmx.de>
Kjell Schubert <kjell.schubert@gmail.com>
Olivier Mengué <dolmen@cpan.org>

View File

@@ -0,0 +1,23 @@
http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
Igor Sysoev.
Additional changes are licensed under the same terms as NGINX and
copyright Joyent, Inc. and other Node contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

View File

@@ -0,0 +1,246 @@
HTTP Parser
===========
[![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser)
This is a parser for HTTP messages written in C. It parses both requests and
responses. The parser is designed to be used in performance HTTP
applications. It does not make any syscalls nor allocations, it does not
buffer data, it can be interrupted at anytime. Depending on your
architecture, it only requires about 40 bytes of data per message
stream (in a web server that is per connection).
Features:
* No dependencies
* Handles persistent streams (keep-alive).
* Decodes chunked encoding.
* Upgrade support
* Defends against buffer overflow attacks.
The parser extracts the following information from HTTP messages:
* Header fields and values
* Content-Length
* Request method
* Response status code
* Transfer-Encoding
* HTTP version
* Request URL
* Message body
Usage
-----
One `http_parser` object is used per TCP connection. Initialize the struct
using `http_parser_init()` and set the callbacks. That might look something
like this for a request parser:
```c
http_parser_settings settings;
settings.on_url = my_url_callback;
settings.on_header_field = my_header_field_callback;
/* ... */
http_parser *parser = malloc(sizeof(http_parser));
http_parser_init(parser, HTTP_REQUEST);
parser->data = my_socket;
```
When data is received on the socket execute the parser and check for errors.
```c
size_t len = 80*1024, nparsed;
char buf[len];
ssize_t recved;
recved = recv(fd, buf, len, 0);
if (recved < 0) {
/* Handle error. */
}
/* Start up / continue the parser.
* Note we pass recved==0 to signal that EOF has been received.
*/
nparsed = http_parser_execute(parser, &settings, buf, recved);
if (parser->upgrade) {
/* handle new protocol */
} else if (nparsed != recved) {
/* Handle error. Usually just close the connection. */
}
```
HTTP needs to know where the end of the stream is. For example, sometimes
servers send responses without Content-Length and expect the client to
consume input (for the body) until EOF. To tell http_parser about EOF, give
`0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors
can still be encountered during an EOF, so one must still be prepared
to receive them.
Scalar valued message information such as `status_code`, `method`, and the
HTTP version are stored in the parser structure. This data is only
temporally stored in `http_parser` and gets reset on each new message. If
this information is needed later, copy it out of the structure during the
`headers_complete` callback.
The parser decodes the transfer-encoding for both requests and responses
transparently. That is, a chunked encoding is decoded before being sent to
the on_body callback.
The Special Problem of Upgrade
------------------------------
HTTP supports upgrading the connection to a different protocol. An
increasingly common example of this is the WebSocket protocol which sends
a request like
GET /demo HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
WebSocket-Protocol: sample
followed by non-HTTP data.
(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the
WebSocket protocol.)
To support this, the parser will treat this as a normal HTTP message without a
body, issuing both on_headers_complete and on_message_complete callbacks. However
http_parser_execute() will stop parsing at the end of the headers and return.
The user is expected to check if `parser->upgrade` has been set to 1 after
`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied
offset by the return value of `http_parser_execute()`.
Callbacks
---------
During the `http_parser_execute()` call, the callbacks set in
`http_parser_settings` will be executed. The parser maintains state and
never looks behind, so buffering the data is not necessary. If you need to
save certain data for later usage, you can do that from the callbacks.
There are two types of callbacks:
* notification `typedef int (*http_cb) (http_parser*);`
Callbacks: on_message_begin, on_headers_complete, on_message_complete.
* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
Callbacks: (requests only) on_url,
(common) on_header_field, on_header_value, on_body;
Callbacks must return 0 on success. Returning a non-zero value indicates
error to the parser, making it exit immediately.
For cases where it is necessary to pass local information to/from a callback,
the `http_parser` object's `data` field can be used.
An example of such a case is when using threads to handle a socket connection,
parse a request, and then give a response over that socket. By instantiation
of a thread-local struct containing relevant data (e.g. accepted socket,
allocated memory for callbacks to write into, etc), a parser's callbacks are
able to communicate data between the scope of the thread and the scope of the
callback in a threadsafe manner. This allows http-parser to be used in
multi-threaded contexts.
Example:
```
typedef struct {
socket_t sock;
void* buffer;
int buf_len;
} custom_data_t;
int my_url_callback(http_parser* parser, const char *at, size_t length) {
/* access to thread local custom_data_t struct.
Use this access save parsed data for later use into thread local
buffer, or communicate over socket
*/
parser->data;
...
return 0;
}
...
void http_parser_thread(socket_t sock) {
int nparsed = 0;
/* allocate memory for user data */
custom_data_t *my_data = malloc(sizeof(custom_data_t));
/* some information for use by callbacks.
* achieves thread -> callback information flow */
my_data->sock = sock;
/* instantiate a thread-local parser */
http_parser *parser = malloc(sizeof(http_parser));
http_parser_init(parser, HTTP_REQUEST); /* initialise parser */
/* this custom data reference is accessible through the reference to the
parser supplied to callback functions */
parser->data = my_data;
http_parser_settings settings; / * set up callbacks */
settings.on_url = my_url_callback;
/* execute parser */
nparsed = http_parser_execute(parser, &settings, buf, recved);
...
/* parsed information copied from callback.
can now perform action on data copied into thread-local memory from callbacks.
achieves callback -> thread information flow */
my_data->buffer;
...
}
```
In case you parse HTTP message in chunks (i.e. `read()` request line
from socket, parse, read half headers, parse, etc) your data callbacks
may be called more than once. Http-parser guarantees that data pointer is only
valid for the lifetime of callback. You can also `read()` into a heap allocated
buffer to avoid copying memory around if this fits your application.
Reading headers may be a tricky task if you read/parse headers partially.
Basically, you need to remember whether last header callback was field or value
and apply the following logic:
(on_header_field and on_header_value shortened to on_h_*)
------------------------ ------------ --------------------------------------------
| State (prev. callback) | Callback | Description/action |
------------------------ ------------ --------------------------------------------
| nothing (first call) | on_h_field | Allocate new buffer and copy callback data |
| | | into it |
------------------------ ------------ --------------------------------------------
| value | on_h_field | New header started. |
| | | Copy current name,value buffers to headers |
| | | list and allocate new buffer for new name |
------------------------ ------------ --------------------------------------------
| field | on_h_field | Previous name continues. Reallocate name |
| | | buffer and append callback data to it |
------------------------ ------------ --------------------------------------------
| field | on_h_value | Value for current header started. Allocate |
| | | new buffer and copy callback data to it |
------------------------ ------------ --------------------------------------------
| value | on_h_value | Value continues. Reallocate value buffer |
| | | and append callback data to it |
------------------------ ------------ --------------------------------------------
Parsing URLs
------------
A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`.
Users of this library may wish to use it to parse URLs constructed from
consecutive `on_url` callbacks.
See examples of reading in headers:
* [partial example](http://gist.github.com/155877) in C
* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,362 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef http_parser_h
#define http_parser_h
#ifdef __cplusplus
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 7
#define HTTP_PARSER_VERSION_PATCH 0
#include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && \
(!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
#include <BaseTsd.h>
#include <stddef.h>
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1
#endif
/* Maximium header size allowed. If the macro is not defined
* before including this header then the default is used. To
* change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
#ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
/* Callbacks should return non-zero to indicate an error. The parser will
* then halt execution.
*
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
* returning '1' from on_headers_complete will tell the parser that it
* should not expect a body. This is used when receiving a response to a
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
* chunked' headers that indicate the presence of a body.
*
* Returning `2` from on_headers_complete will tell parser that it should not
* expect neither a body nor any futher responses on this connection. This is
* useful for handling responses to a CONNECT request which may not contain
* `Upgrade` or `Connection: upgrade` headers.
*
* http_data_cb does not return data chunks. It will be called arbitrarily
* many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data.
*/
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*);
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
/* pathological */ \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
/* WebDAV */ \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
/* subversion */ \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
/* upnp */ \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
/* CalDAV */ \
XX(30, MKCALENDAR, MKCALENDAR) \
/* RFC-2068, section 19.6.1.2 */ \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
enum http_method
{
#define XX(num, name, string) HTTP_##name = num,
HTTP_METHOD_MAP(XX)
#undef XX
};
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_CONNECTION_UPGRADE = 1 << 3
, F_TRAILING = 1 << 4
, F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
, F_CONTENTLENGTH = 1 << 7
};
/* Map for errno-related constants
*
* The provided argument should be a macro that takes 2 arguments.
*/
#define HTTP_ERRNO_MAP(XX) \
/* No error */ \
XX(OK, "success") \
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
XX(CB_chunk_header, "the on_chunk_header callback failed") \
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
XX(INVALID_VERSION, "invalid HTTP version") \
XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_URL, "invalid URL") \
XX(INVALID_HOST, "invalid host") \
XX(INVALID_PORT, "invalid port") \
XX(INVALID_PATH, "invalid path") \
XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_FRAGMENT, "invalid fragment") \
XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
XX(UNEXPECTED_CONTENT_LENGTH, \
"unexpected content-length header") \
XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
XX(INVALID_CONSTANT, "invalid constant string") \
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
};
#undef HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
/** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 7; /* enum state from http_parser.c */
unsigned int header_state : 7; /* enum header_state from http_parser.c */
unsigned int index : 7; /* index into current matcher */
unsigned int lenient_http_headers : 1;
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned int upgrade : 1;
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
};
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
};
enum http_parser_url_fields
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_USERINFO = 6
, UF_MAX = 7
};
/* Result structure for http_parser_parse_url().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
/* Returns the library version. Bits 16-23 contain the major version number,
* bits 8-15 the minor version number and bits 0-7 the patch level.
* Usage example:
*
* unsigned long version = http_parser_version();
* unsigned major = (version >> 16) & 255;
* unsigned minor = (version >> 8) & 255;
* unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/
unsigned long http_parser_version(void);
void http_parser_init(http_parser *parser, enum http_parser_type type);
/* Initialize http_parser_settings members to 0
*/
void http_parser_settings_init(http_parser_settings *settings);
/* Executes the parser. Returns number of parsed bytes. Sets
* `parser->http_errno` on error. */
size_t http_parser_execute(http_parser *parser,
const http_parser_settings *settings,
const char *data,
size_t len);
/* If http_should_keep_alive() in the on_headers_complete or
* on_message_complete callback returns 0, then this should be
* the last message on the connection.
* If you are the server, respond with the "Connection: close" header.
* If you are the client, close the connection.
*/
int http_should_keep_alive(const http_parser *parser);
/* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m);
/* Return a string name of the given error */
const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */
const char *http_errno_description(enum http_errno err);
/* Initialize all http_parser_url members to 0 */
void http_parser_url_init(struct http_parser_url *u);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect,
struct http_parser_url *u);
/* Pause or un-pause the parser; a nonzero value pauses */
void http_parser_pause(http_parser *parser, int paused);
/* Checks if this is the final chunk of the body. */
int http_body_is_final(const http_parser *parser);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,17 @@
//
// Copyright (c) 2013-2017 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)
//
#ifdef _MSC_VER
# pragma warning (push)
# pragma warning (disable: 4127) // conditional expression is constant
# pragma warning (disable: 4244) // integer conversion, possible loss of data
#endif
#include "nodejs-parser/http_parser.c"
#ifdef _MSC_VER
# pragma warning (pop)
#endif

870
test/http/nodejs_parser.hpp Normal file
View File

@@ -0,0 +1,870 @@
//
// Copyright (c) 2013-2017 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)
//
#ifndef BEAST_HTTP_NODEJS_PARSER_HPP
#define BEAST_HTTP_NODEJS_PARSER_HPP
#include "nodejs-parser/http_parser.h"
#include <beast/http/message.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/system/error_code.hpp>
#include <cstdint>
#include <string>
#include <type_traits>
#include <utility>
namespace beast {
namespace http {
namespace detail {
class nodejs_message_category
: public boost::system::error_category
{
public:
const char*
name() const noexcept override
{
return "nodejs-http-error";
}
std::string
message(int ev) const override
{
return http_errno_description(
static_cast<http_errno>(ev));
}
boost::system::error_condition
default_error_condition(int ev) const noexcept override
{
return boost::system::error_condition{ev, *this};
}
bool
equivalent(int ev,
boost::system::error_condition const& condition
) const noexcept override
{
return condition.value() == ev &&
&condition.category() == this;
}
bool
equivalent(boost::system::error_code const& error,
int ev) const noexcept override
{
return error.value() == ev &&
&error.category() == this;
}
};
template<class = void>
boost::system::error_code
make_nodejs_error(int http_errno)
{
static nodejs_message_category const mc{};
return boost::system::error_code{http_errno, mc};
}
inline
char const*
method_to_string(unsigned method)
{
using namespace beast;
switch(static_cast<http_method>(method))
{
case HTTP_DELETE: return "DELETE";
case HTTP_GET: return "GET";
case HTTP_HEAD: return "HEAD";
case HTTP_POST: return "POST";
case HTTP_PUT: return "PUT";
// pathological
case HTTP_CONNECT: return "CONNECT";
case HTTP_OPTIONS: return "OPTIONS";
case HTTP_TRACE: return "TRACE";
// webdav
case HTTP_COPY: return "COPY";
case HTTP_LOCK: return "LOCK";
case HTTP_MKCOL: return "MKCOL";
case HTTP_MOVE: return "MOVE";
case HTTP_PROPFIND: return "PROPFIND";
case HTTP_PROPPATCH: return "PROPPATCH";
case HTTP_SEARCH: return "SEARCH";
case HTTP_UNLOCK: return "UNLOCK";
case HTTP_BIND: return "BIND";
case HTTP_REBIND: return "REBIND";
case HTTP_UNBIND: return "UNBIND";
case HTTP_ACL: return "ACL";
// subversion
case HTTP_REPORT: return "REPORT";
case HTTP_MKACTIVITY: return "MKACTIVITY";
case HTTP_CHECKOUT: return "CHECKOUT";
case HTTP_MERGE: return "MERGE";
// upnp
case HTTP_MSEARCH: return "MSEARCH";
case HTTP_NOTIFY: return "NOTIFY";
case HTTP_SUBSCRIBE: return "SUBSCRIBE";
case HTTP_UNSUBSCRIBE: return "UNSUBSCRIBE";
// RFC-5789
case HTTP_PATCH: return "PATCH";
case HTTP_PURGE: return "PURGE";
// CalDav
case HTTP_MKCALENDAR: return "MKCALENDAR";
// RFC-2068, section 19.6.1.2
case HTTP_LINK: return "LINK";
case HTTP_UNLINK: return "UNLINK";
};
return "<unknown>";
}
} // detail
template<class Derived>
class nodejs_basic_parser
{
http_parser state_;
boost::system::error_code* ec_;
bool complete_ = false;
std::string url_;
std::string status_;
std::string field_;
std::string value_;
public:
using error_code = boost::system::error_code;
nodejs_basic_parser(nodejs_basic_parser&& other);
nodejs_basic_parser&
operator=(nodejs_basic_parser&& other);
nodejs_basic_parser(nodejs_basic_parser const& other);
nodejs_basic_parser& operator=(nodejs_basic_parser const& other);
explicit
nodejs_basic_parser(bool request) noexcept;
bool
complete() const noexcept
{
return complete_;
}
std::size_t
write(void const* data, std::size_t size)
{
error_code ec;
auto const used = write(data, size, ec);
if(ec)
throw system_error{ec};
return used;
}
std::size_t
write(void const* data, std::size_t size,
error_code& ec);
template<class ConstBufferSequence>
std::size_t
write(ConstBufferSequence const& buffers)
{
error_code ec;
auto const used = write(buffers, ec);
if(ec)
throw system_error{ec};
return used;
}
template<class ConstBufferSequence>
std::size_t
write(ConstBufferSequence const& buffers,
error_code& ec);
void
write_eof()
{
error_code ec;
write_eof(ec);
if(ec)
throw system_error{ec};
}
void
write_eof(error_code& ec);
private:
Derived&
impl()
{
return *static_cast<Derived*>(this);
}
template<class C>
class has_on_start_t
{
template<class T, class R =
decltype(std::declval<T>().on_start(), std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<C>(0));
public:
static bool const value = type::value;
};
template<class C>
using has_on_start =
std::integral_constant<bool, has_on_start_t<C>::value>;
void
call_on_start(std::true_type)
{
impl().on_start();
}
void
call_on_start(std::false_type)
{
}
template<class C>
class has_on_field_t
{
template<class T, class R =
decltype(std::declval<T>().on_field(
std::declval<std::string const&>(),
std::declval<std::string const&>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<C>(0));
public:
static bool const value = type::value;
};
template<class C>
using has_on_field =
std::integral_constant<bool, has_on_field_t<C>::value>;
void
call_on_field(std::string const& field,
std::string const& value, std::true_type)
{
impl().on_field(field, value);
}
void
call_on_field(std::string const&, std::string const&,
std::false_type)
{
}
template<class C>
class has_on_headers_complete_t
{
template<class T, class R =
decltype(std::declval<T>().on_headers_complete(
std::declval<error_code&>()), std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<C>(0));
public:
static bool const value = type::value;
};
template<class C>
using has_on_headers_complete =
std::integral_constant<bool, has_on_headers_complete_t<C>::value>;
void
call_on_headers_complete(error_code& ec, std::true_type)
{
impl().on_headers_complete(ec);
}
void
call_on_headers_complete(error_code&, std::false_type)
{
}
template<class C>
class has_on_request_t
{
template<class T, class R =
decltype(std::declval<T>().on_request(
std::declval<unsigned>(), std::declval<std::string>(),
std::declval<int>(), std::declval<int>(),
std::declval<bool>(), std::declval<bool>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<C>(0));
public:
static bool const value = type::value;
};
template<class C>
using has_on_request =
std::integral_constant<bool, has_on_request_t<C>::value>;
void
call_on_request(unsigned method, std::string url,
int major, int minor, bool keep_alive, bool upgrade,
std::true_type)
{
impl().on_request(
method, url, major, minor, keep_alive, upgrade);
}
void
call_on_request(unsigned, std::string, int, int, bool, bool,
std::false_type)
{
}
template<class C>
class has_on_response_t
{
template<class T, class R =
decltype(std::declval<T>().on_response(
std::declval<int>(), std::declval<std::string>,
std::declval<int>(), std::declval<int>(),
std::declval<bool>(), std::declval<bool>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
#if 0
using type = decltype(check<C>(0));
#else
// VFALCO Trait seems broken for http::parser
using type = std::true_type;
#endif
public:
static bool const value = type::value;
};
template<class C>
using has_on_response =
std::integral_constant<bool, has_on_response_t<C>::value>;
bool
call_on_response(int status, std::string text,
int major, int minor, bool keep_alive, bool upgrade,
std::true_type)
{
return impl().on_response(
status, text, major, minor, keep_alive, upgrade);
}
bool
call_on_response(int, std::string, int, int, bool, bool,
std::false_type)
{
// VFALCO Certainly incorrect
return true;
}
template<class C>
class has_on_body_t
{
template<class T, class R =
decltype(std::declval<T>().on_body(
std::declval<void const*>(), std::declval<std::size_t>(),
std::declval<error_code&>()), std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<C>(0));
public:
static bool const value = type::value;
};
template<class C>
using has_on_body =
std::integral_constant<bool, has_on_body_t<C>::value>;
void
call_on_body(void const* data, std::size_t bytes,
error_code& ec, std::true_type)
{
impl().on_body(data, bytes, ec);
}
void
call_on_body(void const*, std::size_t,
error_code&, std::false_type)
{
}
template<class C>
class has_on_complete_t
{
template<class T, class R =
decltype(std::declval<T>().on_complete(), std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<C>(0));
public:
static bool const value = type::value;
};
template<class C>
using has_on_complete =
std::integral_constant<bool, has_on_complete_t<C>::value>;
void
call_on_complete(std::true_type)
{
impl().on_complete();
}
void
call_on_complete(std::false_type)
{
}
void
check_header();
static int cb_message_start(http_parser*);
static int cb_url(http_parser*, char const*, std::size_t);
static int cb_status(http_parser*, char const*, std::size_t);
static int cb_header_field(http_parser*, char const*, std::size_t);
static int cb_header_value(http_parser*, char const*, std::size_t);
static int cb_headers_complete(http_parser*);
static int cb_body(http_parser*, char const*, std::size_t);
static int cb_message_complete(http_parser*);
static int cb_chunk_header(http_parser*);
static int cb_chunk_complete(http_parser*);
struct hooks_t : http_parser_settings
{
hooks_t()
{
http_parser_settings_init(this);
on_message_begin = &nodejs_basic_parser::cb_message_start;
on_url = &nodejs_basic_parser::cb_url;
on_status = &nodejs_basic_parser::cb_status;
on_header_field = &nodejs_basic_parser::cb_header_field;
on_header_value = &nodejs_basic_parser::cb_header_value;
on_headers_complete = &nodejs_basic_parser::cb_headers_complete;
on_body = &nodejs_basic_parser::cb_body;
on_message_complete = &nodejs_basic_parser::cb_message_complete;
on_chunk_header = &nodejs_basic_parser::cb_chunk_header;
on_chunk_complete = &nodejs_basic_parser::cb_chunk_complete;
}
};
static
http_parser_settings const*
hooks();
};
template<class Derived>
template<class ConstBufferSequence>
std::size_t
nodejs_basic_parser<Derived>::write(
ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
std::size_t bytes_used = 0;
for(auto const& buffer : buffers)
{
auto const n = write(
buffer_cast<void const*>(buffer),
buffer_size(buffer), ec);
if(ec)
return 0;
bytes_used += n;
if(complete())
break;
}
return bytes_used;
}
template<class Derived>
http_parser_settings const*
nodejs_basic_parser<Derived>::hooks()
{
static hooks_t const h;
return &h;
}
template<class Derived>
nodejs_basic_parser<Derived>::
nodejs_basic_parser(nodejs_basic_parser&& other)
{
state_ = other.state_;
state_.data = this;
complete_ = other.complete_;
url_ = std::move(other.url_);
status_ = std::move(other.status_);
field_ = std::move(other.field_);
value_ = std::move(other.value_);
}
template<class Derived>
auto
nodejs_basic_parser<Derived>::operator=(nodejs_basic_parser&& other) ->
nodejs_basic_parser&
{
state_ = other.state_;
state_.data = this;
complete_ = other.complete_;
url_ = std::move(other.url_);
status_ = std::move(other.status_);
field_ = std::move(other.field_);
value_ = std::move(other.value_);
return *this;
}
template<class Derived>
nodejs_basic_parser<Derived>::
nodejs_basic_parser(nodejs_basic_parser const& other)
{
state_ = other.state_;
state_.data = this;
complete_ = other.complete_;
url_ = other.url_;
status_ = other.status_;
field_ = other.field_;
value_ = other.value_;
}
template<class Derived>
auto
nodejs_basic_parser<Derived>::
operator=(nodejs_basic_parser const& other) ->
nodejs_basic_parser&
{
state_ = other.state_;
state_.data = this;
complete_ = other.complete_;
url_ = other.url_;
status_ = other.status_;
field_ = other.field_;
value_ = other.value_;
return *this;
}
template<class Derived>
nodejs_basic_parser<Derived>::nodejs_basic_parser(bool request) noexcept
{
state_.data = this;
http_parser_init(&state_, request
? http_parser_type::HTTP_REQUEST
: http_parser_type::HTTP_RESPONSE);
}
template<class Derived>
std::size_t
nodejs_basic_parser<Derived>::write(void const* data,
std::size_t size, error_code& ec)
{
ec_ = &ec;
auto const n = http_parser_execute(
&state_, hooks(),
static_cast<const char*>(data), size);
if(! ec)
ec = detail::make_nodejs_error(
static_cast<int>(state_.http_errno));
if(ec)
return 0;
return n;
}
template<class Derived>
void
nodejs_basic_parser<Derived>::write_eof(error_code& ec)
{
ec_ = &ec;
http_parser_execute(
&state_, hooks(), nullptr, 0);
if(! ec)
ec = detail::make_nodejs_error(
static_cast<int>(state_.http_errno));
}
template<class Derived>
void
nodejs_basic_parser<Derived>::check_header()
{
if(! value_.empty())
{
//detail::trim(value_);
call_on_field(field_, value_,
has_on_field<Derived>{});
field_.clear();
value_.clear();
}
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_message_start(http_parser* p)
{
auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
t.complete_ = false;
t.url_.clear();
t.status_.clear();
t.field_.clear();
t.value_.clear();
t.call_on_start(has_on_start<Derived>{});
return 0;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_url(http_parser* p,
char const* in, std::size_t bytes)
{
auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
t.url_.append(in, bytes);
return 0;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_status(http_parser* p,
char const* in, std::size_t bytes)
{
auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
t.status_.append(in, bytes);
return 0;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_header_field(http_parser* p,
char const* in, std::size_t bytes)
{
auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
t.check_header();
t.field_.append(in, bytes);
return 0;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_header_value(http_parser* p,
char const* in, std::size_t bytes)
{
auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
t.value_.append(in, bytes);
return 0;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_headers_complete(http_parser* p)
{
auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
t.check_header();
t.call_on_headers_complete(*t.ec_,
has_on_headers_complete<Derived>{});
if(*t.ec_)
return 1;
bool const keep_alive =
http_should_keep_alive(p) != 0;
if(p->type == http_parser_type::HTTP_REQUEST)
{
t.call_on_request(p->method, t.url_,
p->http_major, p->http_minor, keep_alive,
p->upgrade, has_on_request<Derived>{});
return 0;
}
return t.call_on_response(p->status_code, t.status_,
p->http_major, p->http_minor, keep_alive,
p->upgrade, has_on_response<Derived>{}) ? 0 : 1;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_body(http_parser* p,
char const* in, std::size_t bytes)
{
auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
t.call_on_body(in, bytes, *t.ec_, has_on_body<Derived>{});
return *t.ec_ ? 1 : 0;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_message_complete(http_parser* p)
{
auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
t.complete_ = true;
t.call_on_complete(has_on_complete<Derived>{});
return 0;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_chunk_header(http_parser*)
{
return 0;
}
template<class Derived>
int
nodejs_basic_parser<Derived>::cb_chunk_complete(http_parser*)
{
return 0;
}
/** A HTTP parser.
The parser may only be used once.
*/
template<bool isRequest, class Body, class Fields>
class nodejs_parser
: public nodejs_basic_parser<nodejs_parser<isRequest, Body, Fields>>
{
using message_type =
message<isRequest, Body, Fields>;
message_type m_;
typename message_type::body_type::reader r_;
bool started_ = false;
public:
nodejs_parser(nodejs_parser&&) = default;
nodejs_parser()
: http::nodejs_basic_parser<nodejs_parser>(isRequest)
, r_(m_)
{
}
/// Returns `true` if at least one byte has been processed
bool
started()
{
return started_;
}
message_type
release()
{
return std::move(m_);
}
private:
friend class http::nodejs_basic_parser<nodejs_parser>;
void
on_start()
{
started_ = true;
}
void
on_field(std::string const& field, std::string const& value)
{
m_.fields.insert(field, value);
}
void
on_headers_complete(error_code&)
{
// vFALCO TODO Decode the Content-Length and
// Transfer-Encoding, see if we can reserve the buffer.
//
// r_.reserve(content_length)
}
bool
on_request(unsigned method, std::string const& url,
int major, int minor, bool /*keep_alive*/, bool /*upgrade*/,
std::true_type)
{
m_.method = detail::method_to_string(method);
m_.url = url;
m_.version = major * 10 + minor;
return true;
}
bool
on_request(unsigned, std::string const&,
int, int, bool, bool,
std::false_type)
{
return true;
}
bool
on_request(unsigned method, std::string const& url,
int major, int minor, bool keep_alive, bool upgrade)
{
return on_request(method, url,
major, minor, keep_alive, upgrade,
std::integral_constant<
bool, message_type::is_request>{});
}
bool
on_response(int status, std::string const& reason,
int major, int minor, bool keep_alive, bool upgrade,
std::true_type)
{
beast::detail::ignore_unused(keep_alive, upgrade);
m_.status = status;
m_.reason = reason;
m_.version = major * 10 + minor;
// VFALCO TODO return expect_body_
return true;
}
bool
on_response(int, std::string const&, int, int, bool, bool,
std::false_type)
{
return true;
}
bool
on_response(int status, std::string const& reason,
int major, int minor, bool keep_alive, bool upgrade)
{
return on_response(
status, reason, major, minor, keep_alive, upgrade,
std::integral_constant<bool, ! message_type::is_request>{});
}
void
on_body(void const* data,
std::size_t size, error_code& ec)
{
r_.write(data, size, ec);
}
void
on_complete()
{
}
};
} // http
} // beast
#endif

9
test/http/parse.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/parse.hpp>

60
test/http/parse_error.cpp Normal file
View File

@@ -0,0 +1,60 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/parse_error.hpp>
#include <beast/unit_test/suite.hpp>
#include <memory>
namespace beast {
namespace http {
class parse_error_test : public unit_test::suite
{
public:
void check(char const* name, parse_error ev)
{
auto const ec = make_error_code(ev);
BEAST_EXPECT(std::string{ec.category().name()} == name);
BEAST_EXPECT(! ec.message().empty());
BEAST_EXPECT(std::addressof(ec.category()) ==
std::addressof(detail::get_parse_error_category()));
BEAST_EXPECT(detail::get_parse_error_category().equivalent(
static_cast<std::underlying_type<parse_error>::type>(ev),
ec.category().default_error_condition(
static_cast<std::underlying_type<parse_error>::type>(ev))));
BEAST_EXPECT(detail::get_parse_error_category().equivalent(
ec, static_cast<std::underlying_type<parse_error>::type>(ev)));
}
void run() override
{
check("http", parse_error::connection_closed);
check("http", parse_error::bad_method);
check("http", parse_error::bad_uri);
check("http", parse_error::bad_version);
check("http", parse_error::bad_crlf);
check("http", parse_error::bad_status);
check("http", parse_error::bad_reason);
check("http", parse_error::bad_field);
check("http", parse_error::bad_value);
check("http", parse_error::bad_content_length);
check("http", parse_error::illegal_content_length);
check("http", parse_error::invalid_chunk_size);
check("http", parse_error::invalid_ext_name);
check("http", parse_error::invalid_ext_val);
check("http", parse_error::header_too_big);
check("http", parse_error::body_too_big);
check("http", parse_error::short_read);
}
};
BEAST_DEFINE_TESTSUITE(parse_error,http,beast);
} // http
} // beast

155
test/http/parser_bench.cpp Normal file
View File

@@ -0,0 +1,155 @@
//
// Copyright (c) 2013-2017 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)
//
#include "nodejs_parser.hpp"
#include "message_fuzz.hpp"
#include <beast/http.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/core/to_string.hpp>
#include <beast/unit_test/suite.hpp>
#include <chrono>
#include <iostream>
#include <vector>
namespace beast {
namespace http {
class parser_bench_test : public beast::unit_test::suite
{
public:
static std::size_t constexpr N = 2000;
using corpus = std::vector<streambuf>;
corpus creq_;
corpus cres_;
std::size_t size_ = 0;
parser_bench_test()
{
creq_ = build_corpus(N/2, std::true_type{});
cres_ = build_corpus(N/2, std::false_type{});
}
corpus
build_corpus(std::size_t n, std::true_type)
{
corpus v;
v.resize(N);
message_fuzz mg;
for(std::size_t i = 0; i < n; ++i)
{
mg.request(v[i]);
size_ += v[i].size();
}
return v;
}
corpus
build_corpus(std::size_t n, std::false_type)
{
corpus v;
v.resize(N);
message_fuzz mg;
for(std::size_t i = 0; i < n; ++i)
{
mg.response(v[i]);
size_ += v[i].size();
}
return v;
}
template<class Parser>
void
testParser(std::size_t repeat, corpus const& v)
{
while(repeat--)
for(auto const& sb : v)
{
Parser p;
error_code ec;
p.write(sb.data(), ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
log << to_string(sb.data()) << std::endl;
}
}
template<class Function>
void
timedTest(std::size_t repeat, std::string const& name, Function&& f)
{
using namespace std::chrono;
using clock_type = std::chrono::high_resolution_clock;
log << name << std::endl;
for(std::size_t trial = 1; trial <= repeat; ++trial)
{
auto const t0 = clock_type::now();
f();
auto const elapsed = clock_type::now() - t0;
log <<
"Trial " << trial << ": " <<
duration_cast<milliseconds>(elapsed).count() << " ms" << std::endl;
}
}
template<bool isRequest>
struct null_parser : basic_parser_v1<isRequest, null_parser<isRequest>>
{
};
void
testSpeed()
{
static std::size_t constexpr Trials = 3;
static std::size_t constexpr Repeat = 50;
log << "sizeof(request parser) == " <<
sizeof(basic_parser_v1<true, null_parser<true>>) << '\n';
log << "sizeof(response parser) == " <<
sizeof(basic_parser_v1<false, null_parser<true>>)<< '\n';
testcase << "Parser speed test, " <<
((Repeat * size_ + 512) / 1024) << "KB in " <<
(Repeat * (creq_.size() + cres_.size())) << " messages";
timedTest(Trials, "nodejs_parser",
[&]
{
testParser<nodejs_parser<
true, streambuf_body, fields>>(
Repeat, creq_);
testParser<nodejs_parser<
false, streambuf_body, fields>>(
Repeat, cres_);
});
timedTest(Trials, "http::basic_parser_v1",
[&]
{
testParser<parser_v1<
true, streambuf_body, fields>>(
Repeat, creq_);
testParser<parser_v1<
false, streambuf_body, fields>>(
Repeat, cres_);
});
pass();
}
void run() override
{
pass();
testSpeed();
}
};
BEAST_DEFINE_TESTSUITE(parser_bench,http,beast);
} // http
} // beast

160
test/http/parser_v1.cpp Normal file
View File

@@ -0,0 +1,160 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/parser_v1.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/http/fields.hpp>
#include <beast/http/header_parser_v1.hpp>
#include <beast/http/parse.hpp>
#include <beast/http/string_body.hpp>
#include <beast/test/string_istream.hpp>
#include <beast/test/yield_to.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace http {
class parser_v1_test
: public beast::unit_test::suite
, public test::enable_yield_to
{
public:
void
testParse()
{
using boost::asio::buffer;
{
error_code ec;
parser_v1<true, string_body,
basic_fields<std::allocator<char>>> p;
std::string const s =
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*";
p.write(buffer(s), ec);
BEAST_EXPECT(! ec);
BEAST_EXPECT(p.complete());
auto m = p.release();
BEAST_EXPECT(m.method == "GET");
BEAST_EXPECT(m.url == "/");
BEAST_EXPECT(m.version == 11);
BEAST_EXPECT(m.fields["User-Agent"] == "test");
BEAST_EXPECT(m.body == "*");
}
{
error_code ec;
parser_v1<false, string_body,
basic_fields<std::allocator<char>>> p;
std::string const s =
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*";
p.write(buffer(s), ec);
BEAST_EXPECT(! ec);
BEAST_EXPECT(p.complete());
auto m = p.release();
BEAST_EXPECT(m.status == 200);
BEAST_EXPECT(m.reason == "OK");
BEAST_EXPECT(m.version == 11);
BEAST_EXPECT(m.fields["Server"] == "test");
BEAST_EXPECT(m.body == "*");
}
// skip body
{
error_code ec;
parser_v1<false, string_body, fields> p;
std::string const s =
"HTTP/1.1 200 Connection Established\r\n"
"Proxy-Agent: Zscaler/5.1\r\n"
"\r\n";
p.set_option(skip_body{true});
p.write(buffer(s), ec);
BEAST_EXPECT(! ec);
BEAST_EXPECT(p.complete());
}
}
void
testWithBody()
{
std::string const raw =
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*";
test::string_istream ss{
ios_, raw, raw.size() - 1};
streambuf rb;
header_parser_v1<true, fields> p0;
parse(ss, rb, p0);
request_header const& reqh = p0.get();
BEAST_EXPECT(reqh.method == "GET");
BEAST_EXPECT(reqh.url == "/");
BEAST_EXPECT(reqh.version == 11);
BEAST_EXPECT(reqh.fields["User-Agent"] == "test");
BEAST_EXPECT(reqh.fields["Content-Length"] == "1");
parser_v1<true, string_body, fields> p =
with_body<string_body>(p0);
BEAST_EXPECT(p.get().method == "GET");
BEAST_EXPECT(p.get().url == "/");
BEAST_EXPECT(p.get().version == 11);
BEAST_EXPECT(p.get().fields["User-Agent"] == "test");
BEAST_EXPECT(p.get().fields["Content-Length"] == "1");
parse(ss, rb, p);
request<string_body, fields> req = p.release();
BEAST_EXPECT(req.body == "*");
}
void
testRegressions()
{
using boost::asio::buffer;
// consecutive empty header values
{
error_code ec;
parser_v1<true, string_body, fields> p;
std::string const s =
"GET / HTTP/1.1\r\n"
"X1:\r\n"
"X2:\r\n"
"X3:x\r\n"
"\r\n";
p.write(buffer(s), ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
BEAST_EXPECT(p.complete());
auto const msg = p.release();
BEAST_EXPECT(msg.fields.exists("X1"));
BEAST_EXPECT(msg.fields["X1"] == "");
BEAST_EXPECT(msg.fields.exists("X2"));
BEAST_EXPECT(msg.fields["X2"] == "");
BEAST_EXPECT(msg.fields.exists("X3"));
BEAST_EXPECT(msg.fields["X3"] == "x");
}
}
void run() override
{
testParse();
testWithBody();
testRegressions();
}
};
BEAST_DEFINE_TESTSUITE(parser_v1,http,beast);
} // http
} // beast

443
test/http/read.cpp Normal file
View File

@@ -0,0 +1,443 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/read.hpp>
#include "fail_parser.hpp"
#include <beast/http/fields.hpp>
#include <beast/http/streambuf_body.hpp>
#include <beast/test/fail_stream.hpp>
#include <beast/test/string_istream.hpp>
#include <beast/test/yield_to.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/spawn.hpp>
#include <atomic>
namespace beast {
namespace http {
class read_test
: public beast::unit_test::suite
, public test::enable_yield_to
{
public:
struct fail_body
{
class reader;
class value_type
{
friend class reader;
std::string s_;
test::fail_counter& fc_;
public:
explicit
value_type(test::fail_counter& fc)
: fc_(fc)
{
}
value_type&
operator=(std::string s)
{
s_ = std::move(s);
return *this;
}
};
class reader
{
value_type& body_;
public:
template<bool isRequest, class Allocator>
explicit
reader(message<isRequest, fail_body, Allocator>& msg) noexcept
: body_(msg.body)
{
}
void
init(error_code& ec) noexcept
{
body_.fc_.fail(ec);
}
void
write(void const* data,
std::size_t size, error_code& ec) noexcept
{
if(body_.fc_.fail(ec))
return;
}
};
};
template<bool isRequest>
void failMatrix(char const* s, yield_context do_yield)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
static std::size_t constexpr limit = 100;
std::size_t n;
auto const len = strlen(s);
for(n = 0; n < limit; ++n)
{
streambuf sb;
sb.commit(buffer_copy(
sb.prepare(len), buffer(s, len)));
test::fail_counter fc(n);
test::fail_stream<
test::string_istream> fs{fc, ios_, ""};
fail_parser<isRequest> p(fc);
error_code ec;
parse(fs, sb, p, ec);
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
static std::size_t constexpr pre = 10;
streambuf sb;
sb.commit(buffer_copy(
sb.prepare(pre), buffer(s, pre)));
test::fail_counter fc(n);
test::fail_stream<test::string_istream> fs{
fc, ios_, std::string{s + pre, len - pre}};
fail_parser<isRequest> p(fc);
error_code ec;
parse(fs, sb, p, ec);
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
streambuf sb;
sb.commit(buffer_copy(
sb.prepare(len), buffer(s, len)));
test::fail_counter fc(n);
test::fail_stream<
test::string_istream> fs{fc, ios_, ""};
fail_parser<isRequest> p(fc);
error_code ec;
async_parse(fs, sb, p, do_yield[ec]);
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
static std::size_t constexpr pre = 10;
streambuf sb;
sb.commit(buffer_copy(
sb.prepare(pre), buffer(s, pre)));
test::fail_counter fc(n);
test::fail_stream<test::string_istream> fs{
fc, ios_, std::string{s + pre, len - pre}};
fail_parser<isRequest> p(fc);
error_code ec;
async_parse(fs, sb, p, do_yield[ec]);
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
streambuf sb;
sb.commit(buffer_copy(
sb.prepare(len), buffer(s, len)));
test::fail_counter fc{n};
test::string_istream ss{ios_, s};
parser_v1<isRequest, fail_body, fields> p{fc};
error_code ec;
parse(ss, sb, p, ec);
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
}
void testThrow()
{
try
{
streambuf sb;
test::string_istream ss(ios_, "GET / X");
parser_v1<true, streambuf_body, fields> p;
parse(ss, sb, p);
fail();
}
catch(std::exception const&)
{
pass();
}
}
void testFailures(yield_context do_yield)
{
char const* req[] = {
"GET / HTTP/1.0\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Empty:\r\n"
"\r\n"
,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 2\r\n"
"\r\n"
"**"
,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"10\r\n"
"****************\r\n"
"0\r\n\r\n"
,
nullptr
};
char const* res[] = {
"HTTP/1.0 200 OK\r\n"
"Server: test\r\n"
"\r\n"
,
"HTTP/1.0 200 OK\r\n"
"Server: test\r\n"
"\r\n"
"***"
,
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 3\r\n"
"\r\n"
"***"
,
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"10\r\n"
"****************\r\n"
"0\r\n\r\n"
,
nullptr
};
for(std::size_t i = 0; req[i]; ++i)
failMatrix<true>(req[i], do_yield);
for(std::size_t i = 0; res[i]; ++i)
failMatrix<false>(res[i], do_yield);
}
void testReadHeaders(yield_context do_yield)
{
static std::size_t constexpr limit = 100;
std::size_t n;
for(n = 0; n < limit; ++n)
{
test::fail_stream<test::string_istream> fs{n, ios_,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
};
request_header m;
try
{
streambuf sb;
read(fs, sb, m);
break;
}
catch(std::exception const&)
{
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<test::string_istream> fs(n, ios_,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 0\r\n"
"\r\n"
);
request_header m;
error_code ec;
streambuf sb;
async_read(fs, sb, m, do_yield[ec]);
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
}
void testRead(yield_context do_yield)
{
static std::size_t constexpr limit = 100;
std::size_t n;
for(n = 0; n < limit; ++n)
{
test::fail_stream<test::string_istream> fs(n, ios_,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 0\r\n"
"\r\n"
);
request<streambuf_body> m;
try
{
streambuf sb;
read(fs, sb, m);
break;
}
catch(std::exception const&)
{
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<test::string_istream> fs(n, ios_,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 0\r\n"
"\r\n"
);
request<streambuf_body> m;
error_code ec;
streambuf sb;
read(fs, sb, m, ec);
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<test::string_istream> fs(n, ios_,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 0\r\n"
"\r\n"
);
request<streambuf_body> m;
error_code ec;
streambuf sb;
async_read(fs, sb, m, do_yield[ec]);
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
}
void testEof(yield_context do_yield)
{
{
streambuf sb;
test::string_istream ss(ios_, "");
parser_v1<true, streambuf_body, fields> p;
error_code ec;
parse(ss, sb, p, ec);
BEAST_EXPECT(ec == boost::asio::error::eof);
}
{
streambuf sb;
test::string_istream ss(ios_, "");
parser_v1<true, streambuf_body, fields> p;
error_code ec;
async_parse(ss, sb, p, do_yield[ec]);
BEAST_EXPECT(ec == boost::asio::error::eof);
}
}
// Ensure completion handlers are not leaked
struct handler
{
static std::atomic<std::size_t>&
count() { static std::atomic<std::size_t> n; return n; }
handler() { ++count(); }
~handler() { --count(); }
handler(handler const&) { ++count(); }
void operator()(error_code const&) const {}
};
void
testIoService()
{
{
// Make sure handlers are not destroyed
// after calling io_service::stop
boost::asio::io_service ios;
test::string_istream is{ios,
"GET / HTTP/1.1\r\n\r\n"};
BEAST_EXPECT(handler::count() == 0);
streambuf sb;
message<true, streambuf_body, fields> m;
async_read(is, sb, m, handler{});
BEAST_EXPECT(handler::count() > 0);
ios.stop();
BEAST_EXPECT(handler::count() > 0);
ios.reset();
BEAST_EXPECT(handler::count() > 0);
ios.run_one();
BEAST_EXPECT(handler::count() == 0);
}
{
// Make sure uninvoked handlers are
// destroyed when calling ~io_service
{
boost::asio::io_service ios;
test::string_istream is{ios,
"GET / HTTP/1.1\r\n\r\n"};
BEAST_EXPECT(handler::count() == 0);
streambuf sb;
message<true, streambuf_body, fields> m;
async_read(is, sb, m, handler{});
BEAST_EXPECT(handler::count() > 0);
}
BEAST_EXPECT(handler::count() == 0);
}
}
void run() override
{
testThrow();
yield_to(&read_test::testFailures, this);
yield_to(&read_test::testReadHeaders, this);
yield_to(&read_test::testRead, this);
yield_to(&read_test::testEof, this);
testIoService();
}
};
BEAST_DEFINE_TESTSUITE(read,http,beast);
} // http
} // beast

29
test/http/reason.cpp Normal file
View File

@@ -0,0 +1,29 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/reason.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace http {
class reason_test : public unit_test::suite
{
public:
void run() override
{
for(int i = 1; i <= 999; ++i)
BEAST_EXPECT(reason_string(i) != nullptr);
}
};
BEAST_DEFINE_TESTSUITE(reason,http,beast);
} // http
} // beast

253
test/http/rfc7230.cpp Normal file
View File

@@ -0,0 +1,253 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/rfc7230.hpp>
#include <beast/http/detail/rfc7230.hpp>
#include <beast/unit_test/suite.hpp>
#include <string>
#include <vector>
namespace beast {
namespace http {
namespace test {
class rfc7230_test : public beast::unit_test::suite
{
public:
static
std::string
fmt(std::string const& s)
{
return '\'' + s + '\'';
}
static
std::string
str(boost::string_ref const& s)
{
return std::string(s.data(), s.size());
}
static
std::string
str(param_list const& c)
{
std::string s;
for(auto const& p : c)
{
s.push_back(';');
s.append(str(p.first));
if(! p.second.empty())
{
s.push_back('=');
s.append(str(p.second));
}
}
return s;
}
void
testParamList()
{
auto const ce =
[&](std::string const& s)
{
auto const got = str(param_list{s});
BEAST_EXPECTS(got == s, fmt(got));
};
auto const cs =
[&](std::string const& s, std::string const& good)
{
ce(good);
auto const got = str(param_list{s});
ce(got);
BEAST_EXPECTS(got == good, fmt(got));
};
auto const cq =
[&](std::string const& s, std::string const& good)
{
auto const got = str(param_list{s});
BEAST_EXPECTS(got == good, fmt(got));
};
ce("");
ce(";x");
ce(";xy");
ce(";x;y");
ce("");
cs(" ;\t i =\t 1 \t", ";i=1");
cq("\t; \t xyz=1 ; ijk=\"q\\\"t\"", ";xyz=1;ijk=q\"t");
ce(";x;y");
// invalid strings
cs(";", "");
cs(";,", "");
cq(";x=,", "");
cq(";xy=\"", "");
cq(";xy=\"\x7f", "");
cq(";xy=\"\\", "");
cq(";xy=\"\\\x01\"", "");
}
static
std::string
str(ext_list const& ex)
{
std::string s;
for(auto const& e : ex)
{
if(! s.empty())
s += ',';
s.append(str(e.first));
s += str(e.second);
}
return s;
}
void
testExtList()
{
auto const ce =
[&](std::string const& s)
{
auto const got = str(ext_list{s});
BEAST_EXPECTS(got == s, fmt(got));
};
auto const cs =
[&](std::string const& s, std::string const& good)
{
ce(good);
auto const got = str(ext_list{s});
ce(got);
BEAST_EXPECTS(got == good, fmt(got));
};
auto const cq =
[&](std::string const& s, std::string const& good)
{
auto const got = str(ext_list{s});
BEAST_EXPECTS(got == good, fmt(got));
};
/*
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
ext = token param-list
param-list = *( OWS ";" OWS param )
param = token OWS "=" OWS ( token / quoted-string )
*/
cs(",", "");
cs(", ", "");
cs(",\t", "");
cs(", \t", "");
cs(" ", "");
cs(" ,", "");
cs("\t,", "");
cs("\t , \t", "");
cs(",,", "");
cs(" , \t,, \t,", "");
cs( "permessage-deflate; client_no_context_takeover; client_max_window_bits",
"permessage-deflate;client_no_context_takeover;client_max_window_bits");
ce("a");
ce("ab");
ce("a,b");
cs(" a ", "a");
cs("\t a, b\t , c\t", "a,b,c");
ce("a;b");
ce("a;b;c");
cs("a; \t i\t=\t \t1\t ", "a;i=1");
ce("a;i=1;j=2;k=3");
ce("a;i=1;j=2;k=3,b;i=4;j=5;k=6");
cq("ab;x=\" \"", "ab;x= ");
cq("ab;x=\"\\\"\"", "ab;x=\"");
BEAST_EXPECT(ext_list{"a,b;i=1,c;j=2;k=3"}.exists("A"));
BEAST_EXPECT(ext_list{"a,b;i=1,c;j=2;k=3"}.exists("b"));
BEAST_EXPECT(! ext_list{"a,b;i=1,c;j=2;k=3"}.exists("d"));
// invalid strings
cs("i j", "i");
cs(";", "");
}
static
std::string
str(token_list const& c)
{
bool first = true;
std::string s;
for(auto const& p : c)
{
if(! first)
s.push_back(',');
s.append(str(p));
first = false;
}
return s;
}
void
testTokenList()
{
auto const ce =
[&](std::string const& s)
{
auto const got = str(token_list{s});
BEAST_EXPECTS(got == s, fmt(got));
};
auto const cs =
[&](std::string const& s, std::string const& good)
{
ce(good);
auto const got = str(token_list{s});
ce(got);
BEAST_EXPECTS(got == good, fmt(got));
};
cs("", "");
cs(" ", "");
cs(" ", "");
cs("\t", "");
cs(" \t ", "");
cs(",", "");
cs(",,", "");
cs(" ,", "");
cs(" , ,", "");
cs(" x", "x");
cs(" \t x", "x");
cs("x ", "x");
cs("x \t", "x");
cs(" \t x \t ", "x");
ce("x,y");
cs("x ,\ty ", "x,y");
cs("x, y, z", "x,y,z");
BEAST_EXPECT(token_list{"a,b,c"}.exists("A"));
BEAST_EXPECT(token_list{"a,b,c"}.exists("b"));
BEAST_EXPECT(! token_list{"a,b,c"}.exists("d"));
// invalid
cs("x y", "x");
}
void
run()
{
testParamList();
testExtList();
testTokenList();
}
};
BEAST_DEFINE_TESTSUITE(rfc7230,http,beast);
} // test
} // http
} // beast

View File

@@ -0,0 +1,48 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/streambuf_body.hpp>
#include <beast/core/to_string.hpp>
#include <beast/http/fields.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/http/read.hpp>
#include <beast/http/write.hpp>
#include <beast/test/string_istream.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/lexical_cast.hpp>
namespace beast {
namespace http {
class streambuf_body_test : public beast::unit_test::suite
{
boost::asio::io_service ios_;
public:
void run() override
{
std::string const s =
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 3\r\n"
"\r\n"
"xyz";
test::string_istream ss(ios_, s);
parser_v1<false, streambuf_body, fields> p;
streambuf sb;
parse(ss, sb, p);
BEAST_EXPECT(to_string(p.get().body.data()) == "xyz");
BEAST_EXPECT(boost::lexical_cast<std::string>(p.get()) == s);
}
};
BEAST_DEFINE_TESTSUITE(streambuf_body,http,beast);
} // http
} // beast

View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/string_body.hpp>

684
test/http/write.cpp Normal file
View File

@@ -0,0 +1,684 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/http/write.hpp>
#include <beast/http/fields.hpp>
#include <beast/http/message.hpp>
#include <beast/http/empty_body.hpp>
#include <beast/http/string_body.hpp>
#include <beast/http/write.hpp>
#include <beast/core/error.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/core/to_string.hpp>
#include <beast/test/fail_stream.hpp>
#include <beast/test/string_ostream.hpp>
#include <beast/test/yield_to.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/error.hpp>
#include <sstream>
#include <string>
namespace beast {
namespace http {
class write_test
: public beast::unit_test::suite
, public test::enable_yield_to
{
public:
struct unsized_body
{
using value_type = std::string;
class writer
{
value_type const& body_;
public:
template<bool isRequest, class Allocator>
explicit
writer(message<isRequest, unsized_body, Allocator> const& msg) noexcept
: body_(msg.body)
{
}
void
init(error_code& ec) noexcept
{
beast::detail::ignore_unused(ec);
}
template<class WriteFunction>
bool
write(error_code&, WriteFunction&& wf) noexcept
{
wf(boost::asio::buffer(body_));
return true;
}
};
};
struct fail_body
{
class writer;
class value_type
{
friend class writer;
std::string s_;
test::fail_counter& fc_;
boost::asio::io_service& ios_;
public:
value_type(test::fail_counter& fc,
boost::asio::io_service& ios)
: fc_(fc)
, ios_(ios)
{
}
boost::asio::io_service&
get_io_service() const
{
return ios_;
}
value_type&
operator=(std::string s)
{
s_ = std::move(s);
return *this;
}
};
class writer
{
std::size_t n_ = 0;
value_type const& body_;
public:
template<bool isRequest, class Allocator>
explicit
writer(message<isRequest, fail_body, Allocator> const& msg) noexcept
: body_(msg.body)
{
}
void
init(error_code& ec) noexcept
{
body_.fc_.fail(ec);
}
template<class WriteFunction>
bool
write(error_code& ec, WriteFunction&& wf) noexcept
{
if(body_.fc_.fail(ec))
return false;
if(n_ >= body_.s_.size())
return true;
wf(boost::asio::buffer(body_.s_.data() + n_, 1));
++n_;
return n_ == body_.s_.size();
}
};
};
template<bool isRequest, class Body, class Fields>
std::string
str(message<isRequest, Body, Fields> const& m)
{
test::string_ostream ss(ios_);
write(ss, m);
return ss.str;
}
void
testAsyncWriteHeaders(yield_context do_yield)
{
{
header<true, fields> m;
m.version = 11;
m.method = "GET";
m.url = "/";
m.fields.insert("User-Agent", "test");
error_code ec;
test::string_ostream ss{ios_};
async_write(ss, m, do_yield[ec]);
if(BEAST_EXPECTS(! ec, ec.message()))
BEAST_EXPECT(ss.str ==
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"\r\n");
}
{
header<false, fields> m;
m.version = 10;
m.status = 200;
m.reason = "OK";
m.fields.insert("Server", "test");
m.fields.insert("Content-Length", "5");
error_code ec;
test::string_ostream ss{ios_};
async_write(ss, m, do_yield[ec]);
if(BEAST_EXPECTS(! ec, ec.message()))
BEAST_EXPECT(ss.str ==
"HTTP/1.0 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 5\r\n"
"\r\n");
}
}
void
testAsyncWrite(yield_context do_yield)
{
{
message<false, string_body, fields> m;
m.version = 10;
m.status = 200;
m.reason = "OK";
m.fields.insert("Server", "test");
m.fields.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
test::string_ostream ss{ios_};
async_write(ss, m, do_yield[ec]);
if(BEAST_EXPECTS(! ec, ec.message()))
BEAST_EXPECT(ss.str ==
"HTTP/1.0 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****");
}
{
message<false, string_body, fields> m;
m.version = 11;
m.status = 200;
m.reason = "OK";
m.fields.insert("Server", "test");
m.fields.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
test::string_ostream ss(ios_);
async_write(ss, m, do_yield[ec]);
if(BEAST_EXPECTS(! ec, ec.message()))
BEAST_EXPECT(ss.str ==
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"5\r\n"
"*****\r\n"
"0\r\n\r\n");
}
}
void
testFailures(yield_context do_yield)
{
static std::size_t constexpr limit = 100;
std::size_t n;
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.fields.insert("Content-Length", "5");
m.body = "*****";
try
{
write(fs, m);
BEAST_EXPECT(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"
);
pass();
break;
}
catch(std::exception const&)
{
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.fields.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
write(fs, m, ec);
if(ec == boost::asio::error::eof)
{
BEAST_EXPECT(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"0\r\n\r\n"
);
break;
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.fields.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
async_write(fs, m, do_yield[ec]);
if(ec == boost::asio::error::eof)
{
BEAST_EXPECT(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"0\r\n\r\n"
);
break;
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.fields.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
write(fs, m, ec);
if(! ec)
{
BEAST_EXPECT(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"
);
break;
}
}
BEAST_EXPECT(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.fields.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
async_write(fs, m, do_yield[ec]);
if(! ec)
{
BEAST_EXPECT(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"
);
break;
}
}
BEAST_EXPECT(n < limit);
}
void
testOutput()
{
// auto content-length HTTP/1.0
{
message<true, string_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.body = "*";
prepare(m);
BEAST_EXPECT(str(m) ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*"
);
}
// keep-alive HTTP/1.0
{
message<true, string_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.body = "*";
prepare(m, connection::keep_alive);
BEAST_EXPECT(str(m) ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"Connection: keep-alive\r\n"
"\r\n"
"*"
);
}
// upgrade HTTP/1.0
{
message<true, string_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.body = "*";
try
{
prepare(m, connection::upgrade);
fail();
}
catch(std::exception const&)
{
pass();
}
}
// no content-length HTTP/1.0
{
message<true, unsized_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 10;
m.fields.insert("User-Agent", "test");
m.body = "*";
prepare(m);
test::string_ostream ss(ios_);
error_code ec;
write(ss, m, ec);
BEAST_EXPECT(ec == boost::asio::error::eof);
BEAST_EXPECT(ss.str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"\r\n"
"*"
);
}
// auto content-length HTTP/1.1
{
message<true, string_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.fields.insert("User-Agent", "test");
m.body = "*";
prepare(m);
BEAST_EXPECT(str(m) ==
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*"
);
}
// close HTTP/1.1
{
message<true, string_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.fields.insert("User-Agent", "test");
m.body = "*";
prepare(m, connection::close);
test::string_ostream ss(ios_);
error_code ec;
write(ss, m, ec);
BEAST_EXPECT(ec == boost::asio::error::eof);
BEAST_EXPECT(ss.str ==
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"Connection: close\r\n"
"\r\n"
"*"
);
}
// upgrade HTTP/1.1
{
message<true, empty_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.fields.insert("User-Agent", "test");
prepare(m, connection::upgrade);
BEAST_EXPECT(str(m) ==
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Connection: upgrade\r\n"
"\r\n"
);
}
// no content-length HTTP/1.1
{
message<true, unsized_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.fields.insert("User-Agent", "test");
m.body = "*";
prepare(m);
test::string_ostream ss(ios_);
error_code ec;
write(ss, m, ec);
BEAST_EXPECT(ss.str ==
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"1\r\n"
"*\r\n"
"0\r\n\r\n"
);
}
}
void test_std_ostream()
{
// Conversion to std::string via operator<<
message<true, string_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.fields.insert("User-Agent", "test");
m.body = "*";
BEAST_EXPECT(boost::lexical_cast<std::string>(m) ==
"GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*");
BEAST_EXPECT(boost::lexical_cast<std::string>(m.base()) ==
"GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n");
// Cause exceptions in operator<<
{
std::stringstream ss;
ss.setstate(ss.rdstate() |
std::stringstream::failbit);
try
{
// header
ss << m.base();
fail("", __FILE__, __LINE__);
}
catch(std::exception const&)
{
pass();
}
try
{
// message
ss << m;
fail("", __FILE__, __LINE__);
}
catch(std::exception const&)
{
pass();
}
}
}
void testOstream()
{
message<true, string_body, fields> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.fields.insert("User-Agent", "test");
m.body = "*";
prepare(m);
std::stringstream ss;
ss.setstate(ss.rdstate() |
std::stringstream::failbit);
try
{
ss << m;
fail();
}
catch(std::exception const&)
{
pass();
}
}
// Ensure completion handlers are not leaked
struct handler
{
static std::atomic<std::size_t>&
count() { static std::atomic<std::size_t> n; return n; }
handler() { ++count(); }
~handler() { --count(); }
handler(handler const&) { ++count(); }
void operator()(error_code const&) const {}
};
void
testIoService()
{
{
// Make sure handlers are not destroyed
// after calling io_service::stop
boost::asio::io_service ios;
test::string_ostream os{ios};
BEAST_EXPECT(handler::count() == 0);
message<true, string_body, fields> m;
m.method = "GET";
m.version = 11;
m.url = "/";
m.fields["Content-Length"] = "5";
m.body = "*****";
async_write(os, m, handler{});
BEAST_EXPECT(handler::count() > 0);
ios.stop();
BEAST_EXPECT(handler::count() > 0);
ios.reset();
BEAST_EXPECT(handler::count() > 0);
ios.run_one();
BEAST_EXPECT(handler::count() == 0);
}
{
// Make sure uninvoked handlers are
// destroyed when calling ~io_service
{
boost::asio::io_service ios;
test::string_ostream is{ios};
BEAST_EXPECT(handler::count() == 0);
message<true, string_body, fields> m;
m.method = "GET";
m.version = 11;
m.url = "/";
m.fields["Content-Length"] = "5";
m.body = "*****";
async_write(is, m, handler{});
BEAST_EXPECT(handler::count() > 0);
}
BEAST_EXPECT(handler::count() == 0);
}
}
void run() override
{
yield_to(&write_test::testAsyncWriteHeaders, this);
yield_to(&write_test::testAsyncWrite, this);
yield_to(&write_test::testFailures, this);
testOutput();
test_std_ostream();
testOstream();
testIoService();
}
};
BEAST_DEFINE_TESTSUITE(write,http,beast);
} // http
} // beast

9
test/version.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/version.hpp>

9
test/websocket.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/websocket.hpp>

View File

@@ -0,0 +1,31 @@
# Part of Beast
GroupSources(extras/beast extras)
GroupSources(include/beast beast)
GroupSources(test/websocket "/")
add_executable (websocket-tests
${BEAST_INCLUDES}
${EXTRAS_INCLUDES}
../../extras/beast/unit_test/main.cpp
websocket_async_echo_server.hpp
websocket_sync_echo_server.hpp
error.cpp
option.cpp
rfc6455.cpp
stream.cpp
teardown.cpp
frame.cpp
mask.cpp
utf8_checker.cpp
)
if (NOT WIN32)
target_link_libraries(websocket-tests ${Boost_LIBRARIES} Threads::Threads)
else()
target_link_libraries(websocket-tests ${Boost_LIBRARIES})
endif()
if (MINGW)
set_target_properties(websocket-tests PROPERTIES COMPILE_FLAGS "-Wa,-mbig-obj -Og")
endif()

54
test/websocket/error.cpp Normal file
View File

@@ -0,0 +1,54 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/websocket/error.hpp>
#include <beast/unit_test/suite.hpp>
#include <memory>
namespace beast {
namespace websocket {
class error_test : public unit_test::suite
{
public:
void check(char const* name, error ev)
{
auto const ec = make_error_code(ev);
BEAST_EXPECT(std::string{ec.category().name()} == name);
BEAST_EXPECT(! ec.message().empty());
BEAST_EXPECT(std::addressof(ec.category()) ==
std::addressof(detail::get_error_category()));
BEAST_EXPECT(detail::get_error_category().equivalent(
static_cast<std::underlying_type<error>::type>(ev),
ec.category().default_error_condition(
static_cast<std::underlying_type<error>::type>(ev))));
BEAST_EXPECT(detail::get_error_category().equivalent(
ec, static_cast<std::underlying_type<error>::type>(ev)));
}
void run() override
{
check("websocket", error::closed);
check("websocket", error::failed);
check("websocket", error::handshake_failed);
check("websocket", error::keep_alive);
check("websocket", error::response_malformed);
check("websocket", error::response_failed);
check("websocket", error::response_denied);
check("websocket", error::request_malformed);
check("websocket", error::request_invalid);
check("websocket", error::request_denied);
check("websocket", error::general);
}
};
BEAST_DEFINE_TESTSUITE(error,websocket,beast);
} // websocket
} // beast

241
test/websocket/frame.cpp Normal file
View File

@@ -0,0 +1,241 @@
//
// Copyright (c) 2013-2017 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)
//
#include <beast/websocket/detail/frame.hpp>
#include <beast/websocket/detail/stream_base.hpp>
#include <beast/unit_test/suite.hpp>
#include <initializer_list>
#include <climits>
namespace beast {
namespace websocket {
namespace detail {
static
bool
operator==(frame_header const& lhs, frame_header const& rhs)
{
return
lhs.op == rhs.op &&
lhs.fin == rhs.fin &&
lhs.mask == rhs.mask &&
lhs.rsv1 == rhs.rsv1 &&
lhs.rsv2 == rhs.rsv2 &&
lhs.rsv3 == rhs.rsv3 &&
lhs.len == rhs.len &&
lhs.key == rhs.key;
}
class frame_test : public beast::unit_test::suite
{
public:
void testCloseCodes()
{
BEAST_EXPECT(! is_valid(0));
BEAST_EXPECT(! is_valid(1));
BEAST_EXPECT(! is_valid(999));
BEAST_EXPECT(! is_valid(1004));
BEAST_EXPECT(! is_valid(1005));
BEAST_EXPECT(! is_valid(1006));
BEAST_EXPECT(! is_valid(1016));
BEAST_EXPECT(! is_valid(2000));
BEAST_EXPECT(! is_valid(2999));
BEAST_EXPECT(is_valid(1000));
BEAST_EXPECT(is_valid(1002));
BEAST_EXPECT(is_valid(3000));
BEAST_EXPECT(is_valid(4000));
BEAST_EXPECT(is_valid(5000));
}
struct test_fh : frame_header
{
test_fh()
{
op = opcode::text;
fin = false;
mask = false;
rsv1 = false;
rsv2 = false;
rsv3 = false;
len = 0;
key = 0;
}
};
void testFrameHeader()
{
// good frame fields
{
role_type role = role_type::client;
auto check =
[&](frame_header const& fh)
{
fh_streambuf sb;
write(sb, fh);
close_code::value code;
stream_base stream;
stream.open(role);
detail::frame_header fh1;
auto const n =
stream.read_fh1(fh1, sb, code);
if(! BEAST_EXPECT(! code))
return;
if(! BEAST_EXPECT(sb.size() == n))
return;
stream.read_fh2(fh1, sb, code);
if(! BEAST_EXPECT(! code))
return;
if(! BEAST_EXPECT(sb.size() == 0))
return;
BEAST_EXPECT(fh1 == fh);
};
test_fh fh;
check(fh);
role = role_type::server;
fh.mask = true;
fh.key = 1;
check(fh);
fh.len = 1;
check(fh);
fh.len = 126;
check(fh);
fh.len = 65535;
check(fh);
fh.len = 65536;
check(fh);
fh.len = 65537;
check(fh);
}
// bad frame fields
{
role_type role = role_type::client;
auto check =
[&](frame_header const& fh)
{
fh_streambuf sb;
write(sb, fh);
close_code::value code;
stream_base stream;
stream.open(role);
detail::frame_header fh1;
auto const n =
stream.read_fh1(fh1, sb, code);
if(code)
{
pass();
return;
}
if(! BEAST_EXPECT(sb.size() == n))
return;
stream.read_fh2(fh1, sb, code);
if(! BEAST_EXPECT(code))
return;
if(! BEAST_EXPECT(sb.size() == 0))
return;
};
test_fh fh;
fh.op = opcode::close;
fh.fin = true;
fh.len = 126;
check(fh);
fh.len = 0;
fh.rsv1 = true;
check(fh);
fh.rsv1 = false;
fh.rsv2 = true;
check(fh);
fh.rsv2 = false;
fh.rsv3 = true;
check(fh);
fh.rsv3 = false;
fh.op = opcode::rsv3;
check(fh);
fh.op = opcode::text;
fh.op = opcode::ping;
fh.fin = false;
check(fh);
fh.fin = true;
fh.mask = true;
check(fh);
role = role_type::server;
fh.mask = false;
check(fh);
}
}
void bad(std::initializer_list<std::uint8_t> bs)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
static role_type constexpr role = role_type::client;
std::vector<std::uint8_t> v{bs};
fh_streambuf sb;
sb.commit(buffer_copy(sb.prepare(v.size()), buffer(v)));
stream_base stream;
stream.open(role);
close_code::value code;
detail::frame_header fh;
auto const n =
stream.read_fh1(fh, sb, code);
if(code)
{
pass();
return;
}
if(! BEAST_EXPECT(sb.size() == n))
return;
stream.read_fh2(fh, sb, code);
if(! BEAST_EXPECT(code))
return;
if(! BEAST_EXPECT(sb.size() == 0))
return;
}
void testBadFrameHeaders()
{
// bad frame fields
//
// can't be created by the library
// so we produce them manually.
bad({0, 126, 0, 125});
bad({0, 127, 0, 0, 0, 0, 0, 0, 255, 255});
}
void run() override
{
testCloseCodes();
testFrameHeader();
testBadFrameHeaders();
}
};
BEAST_DEFINE_TESTSUITE(frame,websocket,beast);
} // detail
} // websocket
} // beast

55
test/websocket/mask.cpp Normal file
View File

@@ -0,0 +1,55 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/websocket/detail/mask.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace websocket {
namespace detail {
class mask_test : public beast::unit_test::suite
{
public:
struct test_generator
{
using result_type = std::uint32_t;
result_type n = 0;
void
seed(std::seed_seq const&)
{
}
void
seed(result_type const&)
{
}
std::uint32_t
operator()()
{
return n++;
}
};
void run() override
{
maskgen_t<test_generator> mg;
BEAST_EXPECT(mg() != 0);
}
};
BEAST_DEFINE_TESTSUITE(mask,websocket,beast);
} // detail
} // websocket
} // beast

View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/websocket/option.hpp>

View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/websocket/rfc6455.hpp>

1396
test/websocket/stream.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/websocket/teardown.hpp>

View File

@@ -0,0 +1,410 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/websocket/detail/utf8_checker.hpp>
#include <beast/core/consuming_buffers.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/unit_test/suite.hpp>
#include <array>
namespace beast {
namespace websocket {
namespace detail {
class utf8_checker_test : public beast::unit_test::suite
{
public:
void
testOneByteSequence()
{
utf8_checker utf8;
std::array<std::uint8_t, 256> buf =
([]()
{
std::array<std::uint8_t, 256> values;
std::uint8_t i = 0;
for(auto& c : values)
c = i++;
return values;
})();
// Valid range 0-127
BEAST_EXPECT(utf8.write(buf.data(), 128));
BEAST_EXPECT(utf8.finish());
// Invalid range 128-193
for(auto it = std::next(buf.begin(), 128);
it != std::next(buf.begin(), 194); ++it)
BEAST_EXPECT(! utf8.write(&(*it), 1));
// Invalid range 245-255
for(auto it = std::next(buf.begin(), 245);
it != buf.end(); ++it)
BEAST_EXPECT(! utf8.write(&(*it), 1));
// Invalid sequence
std::fill(buf.begin(), buf.end(), 0xFF);
BEAST_EXPECT(! utf8.write(&buf.front(), buf.size()));
}
void
testTwoByteSequence()
{
utf8_checker utf8;
std::uint8_t buf[2];
for(auto i = 194; i <= 223; ++i)
{
// First byte valid range 194-223
buf[0] = static_cast<std::uint8_t>(i);
for(auto j = 128; j <= 191; ++j)
{
// Second byte valid range 128-191
buf[1] = static_cast<std::uint8_t>(j);
BEAST_EXPECT(utf8.write(buf, 2));
BEAST_EXPECT(utf8.finish());
}
for(auto j = 0; j <= 127; ++j)
{
// Second byte invalid range 0-127
buf[1] = static_cast<std::uint8_t>(j);
BEAST_EXPECT(! utf8.write(buf, 2));
}
for(auto j = 192; j <= 255; ++j)
{
// Second byte invalid range 192-255
buf[1] = static_cast<std::uint8_t>(j);
BEAST_EXPECT(! utf8.write(buf, 2));
}
// Segmented sequence second byte invalid
BEAST_EXPECT(utf8.write(buf, 1));
BEAST_EXPECT(! utf8.write(&buf[1], 1));
utf8.reset();
}
}
void
testThreeByteSequence()
{
utf8_checker utf8;
std::uint8_t buf[3];
for(auto i = 224; i <= 239; ++i)
{
// First byte valid range 224-239
buf[0] = static_cast<std::uint8_t>(i);
std::int32_t const b = (i == 224 ? 160 : 128);
std::int32_t const e = (i == 237 ? 159 : 191);
for(auto j = b; j <= e; ++j)
{
// Second byte valid range 128-191 or 160-191 or 128-159
buf[1] = static_cast<std::uint8_t>(j);
for(auto k = 128; k <= 191; ++k)
{
// Third byte valid range 128-191
buf[2] = static_cast<std::uint8_t>(k);
BEAST_EXPECT(utf8.write(buf, 3));
BEAST_EXPECT(utf8.finish());
// Segmented sequence
BEAST_EXPECT(utf8.write(buf, 1));
BEAST_EXPECT(utf8.write(&buf[1], 2));
utf8.reset();
// Segmented sequence
BEAST_EXPECT(utf8.write(buf, 2));
BEAST_EXPECT(utf8.write(&buf[2], 1));
utf8.reset();
if (i == 224)
{
for (auto l = 0; l < b; ++l)
{
// Second byte invalid range 0-127 or 0-159
buf[1] = static_cast<std::uint8_t>(l);
BEAST_EXPECT(! utf8.write(buf, 3));
if (l > 127)
{
// Segmented sequence second byte invalid
BEAST_EXPECT(! utf8.write(buf, 2));
utf8.reset();
}
}
buf[1] = static_cast<std::uint8_t>(j);
}
else if (i == 237)
{
for (auto l = e + 1; l <= 255; ++l)
{
// Second byte invalid range 160-255 or 192-255
buf[1] = static_cast<std::uint8_t>(l);
BEAST_EXPECT(!utf8.write(buf, 3));
if (l > 159)
{
// Segmented sequence second byte invalid
BEAST_EXPECT(! utf8.write(buf, 2));
utf8.reset();
}
}
buf[1] = static_cast<std::uint8_t>(j);
}
}
for(auto k = 0; k <= 127; ++k)
{
// Third byte invalid range 0-127
buf[2] = static_cast<std::uint8_t>(k);
BEAST_EXPECT(! utf8.write(buf, 3));
}
for(auto k = 192; k <= 255; ++k)
{
// Third byte invalid range 192-255
buf[2] = static_cast<std::uint8_t>(k);
BEAST_EXPECT(! utf8.write(buf, 3));
}
// Segmented sequence third byte invalid
BEAST_EXPECT(utf8.write(buf, 2));
BEAST_EXPECT(! utf8.write(&buf[2], 1));
utf8.reset();
}
for(auto j = 0; j < b; ++j)
{
// Second byte invalid range 0-127 or 0-159
buf[1] = static_cast<std::uint8_t>(j);
BEAST_EXPECT(! utf8.write(buf, 3));
}
for(auto j = e + 1; j <= 255; ++j)
{
// Second byte invalid range 160-255 or 192-255
buf[1] = static_cast<std::uint8_t>(j);
BEAST_EXPECT(! utf8.write(buf, 3));
}
// Segmented sequence second byte invalid
BEAST_EXPECT(utf8.write(buf, 1));
BEAST_EXPECT(! utf8.write(&buf[1], 1));
utf8.reset();
}
}
void
testFourByteSequence()
{
using boost::asio::const_buffers_1;
utf8_checker utf8;
std::uint8_t buf[4];
for(auto i = 240; i <= 244; ++i)
{
// First byte valid range 240-244
buf[0] = static_cast<std::uint8_t>(i);
std::int32_t const b = (i == 240 ? 144 : 128);
std::int32_t const e = (i == 244 ? 143 : 191);
for(auto j = b; j <= e; ++j)
{
// Second byte valid range 144-191 or 128-191 or 128-143
buf[1] = static_cast<std::uint8_t>(j);
for(auto k = 128; k <= 191; ++k)
{
// Third byte valid range 128-191
buf[2] = static_cast<std::uint8_t>(k);
for(auto n = 128; n <= 191; ++n)
{
// Fourth byte valid range 128-191
buf[3] = static_cast<std::uint8_t>(n);
BEAST_EXPECT(utf8.write(const_buffers_1{buf, 4}));
BEAST_EXPECT(utf8.finish());
// Segmented sequence
BEAST_EXPECT(utf8.write(buf, 1));
BEAST_EXPECT(utf8.write(&buf[1], 3));
utf8.reset();
// Segmented sequence
BEAST_EXPECT(utf8.write(buf, 2));
BEAST_EXPECT(utf8.write(&buf[2], 2));
utf8.reset();
// Segmented sequence
BEAST_EXPECT(utf8.write(buf, 3));
BEAST_EXPECT(utf8.write(&buf[3], 1));
utf8.reset();
if (i == 240)
{
for (auto l = 0; l < b; ++l)
{
// Second byte invalid range 0-127 or 0-143
buf[1] = static_cast<std::uint8_t>(l);
BEAST_EXPECT(! utf8.write(buf, 4));
if (l > 127)
{
// Segmented sequence second byte invalid
BEAST_EXPECT(! utf8.write(buf, 2));
utf8.reset();
}
}
buf[1] = static_cast<std::uint8_t>(j);
}
else if (i == 244)
{
for (auto l = e + 1; l <= 255; ++l)
{
// Second byte invalid range 144-255 or 192-255
buf[1] = static_cast<std::uint8_t>(l);
BEAST_EXPECT(! utf8.write(buf, 4));
if (l > 143)
{
// Segmented sequence second byte invalid
BEAST_EXPECT(! utf8.write(buf, 2));
utf8.reset();
}
}
buf[1] = static_cast<std::uint8_t>(j);
}
}
for(auto n = 0; n <= 127; ++n)
{
// Fourth byte invalid range 0-127
buf[3] = static_cast<std::uint8_t>(n);
BEAST_EXPECT(! utf8.write(const_buffers_1{buf, 4}));
}
for(auto n = 192; n <= 255; ++n)
{
// Fourth byte invalid range 192-255
buf[3] = static_cast<std::uint8_t>(n);
BEAST_EXPECT(! utf8.write(buf, 4));
}
// Segmented sequence fourth byte invalid
BEAST_EXPECT(utf8.write(buf, 3));
BEAST_EXPECT(! utf8.write(&buf[3], 1));
utf8.reset();
}
for(auto k = 0; k <= 127; ++k)
{
// Third byte invalid range 0-127
buf[2] = static_cast<std::uint8_t>(k);
BEAST_EXPECT(! utf8.write(buf, 4));
}
for(auto k = 192; k <= 255; ++k)
{
// Third byte invalid range 192-255
buf[2] = static_cast<std::uint8_t>(k);
BEAST_EXPECT(! utf8.write(buf, 4));
}
// Segmented sequence third byte invalid
BEAST_EXPECT(utf8.write(buf, 2));
BEAST_EXPECT(! utf8.write(&buf[2], 1));
utf8.reset();
}
for(auto j = 0; j < b; ++j)
{
// Second byte invalid range 0-127 or 0-143
buf[1] = static_cast<std::uint8_t>(j);
BEAST_EXPECT(! utf8.write(buf, 4));
}
for(auto j = e + 1; j <= 255; ++j)
{
// Second byte invalid range 144-255 or 192-255
buf[1] = static_cast<std::uint8_t>(j);
BEAST_EXPECT(! utf8.write(buf, 4));
}
// Segmented sequence second byte invalid
BEAST_EXPECT(utf8.write(buf, 1));
BEAST_EXPECT(! utf8.write(&buf[1], 1));
utf8.reset();
}
for (auto i = 245; i <= 255; ++i)
{
// First byte invalid range 245-255
buf[0] = static_cast<std::uint8_t>(i);
BEAST_EXPECT(! utf8.write(buf, 4));
}
}
void
testWithStreamBuffer()
{
using namespace boost::asio;
{
// Valid UTF8 encoded text
std::vector<std::vector<std::uint8_t>> const data{{
0x48,0x65,0x69,0x7A,0xC3,0xB6,0x6C,0x72,0xC3,0xBC,0x63,0x6B,
0x73,0x74,0x6F,0xC3,0x9F,0x61,0x62,0x64,0xC3,0xA4,0x6D,0x70,
0x66,0x75,0x6E,0x67
}, {
0xCE,0x93,0xCE,0xB1,0xCE,0xB6,0xCE,0xAD,0xCE,0xB5,0xCF,0x82,
0x20,0xCE,0xBA,0xCE,0xB1,0xE1,0xBD,0xB6,0x20,0xCE,0xBC,0xCF,
0x85,0xCF,0x81,0xCF,0x84,0xCE,0xB9,0xE1,0xBD,0xB2,0xCF,0x82,
0x20,0xCE,0xB4,0xE1,0xBD,0xB2,0xCE,0xBD,0x20,0xCE,0xB8,0xE1,
0xBD,0xB0,0x20,0xCE,0xB2,0xCF,0x81,0xE1,0xBF,0xB6,0x20,0xCF,
0x80,0xCE,0xB9,0xE1,0xBD,0xB0,0x20,0xCF,0x83,0xCF,0x84,0xE1,
0xBD,0xB8,0x20,0xCF,0x87,0xCF,0x81,0xCF,0x85,0xCF,0x83,0xCE,
0xB1,0xCF,0x86,0xE1,0xBD,0xB6,0x20,0xCE,0xBE,0xCE,0xAD,0xCF,
0x86,0xCF,0x89,0xCF,0x84,0xCE,0xBF
}, {
0xC3,0x81,0x72,0x76,0xC3,0xAD,0x7A,0x74,0xC5,0xB1,0x72,0xC5,
0x91,0x20,0x74,0xC3,0xBC,0x6B,0xC3,0xB6,0x72,0x66,0xC3,0xBA,
0x72,0xC3,0xB3,0x67,0xC3,0xA9,0x70
}, {
240, 144, 128, 128
}
};
utf8_checker utf8;
for(auto const& s : data)
{
static std::size_t constexpr size = 3;
std::size_t n = s.size();
consuming_buffers<
boost::asio::const_buffers_1> cb{
boost::asio::const_buffers_1(s.data(), n)};
streambuf sb{size};
while(n)
{
auto const amount = (std::min)(n, size);
sb.commit(buffer_copy(sb.prepare(amount), cb));
cb.consume(amount);
n -= amount;
}
BEAST_EXPECT(utf8.write(sb.data()));
BEAST_EXPECT(utf8.finish());
}
}
}
void run() override
{
testOneByteSequence();
testTwoByteSequence();
testThreeByteSequence();
testFourByteSequence();
testWithStreamBuffer();
}
};
BEAST_DEFINE_TESTSUITE(utf8_checker,websocket,beast);
} // detail
} // websocket
} // beast

View File

@@ -0,0 +1,429 @@
//
// Copyright (c) 2013-2017 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)
//
#ifndef BEAST_WEBSOCKET_ASYNC_ECHO_SERVER_HPP
#define BEAST_WEBSOCKET_ASYNC_ECHO_SERVER_HPP
#include <beast/core/placeholders.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/websocket/stream.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <ostream>
#include <string>
#include <thread>
#include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <utility>
namespace websocket {
/** Asynchronous WebSocket echo client/server
*/
class async_echo_server
{
public:
using error_code = beast::error_code;
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
using endpoint_type = boost::asio::ip::tcp::endpoint;
private:
struct identity
{
template<class Body, class Fields>
void
operator()(beast::http::message<
true, Body, Fields>& req) const
{
req.fields.replace("User-Agent", "async_echo_client");
}
template<class Body, class Fields>
void
operator()(beast::http::message<
false, Body, Fields>& resp) const
{
resp.fields.replace("Server", "async_echo_server");
}
};
/** A container of type-erased option setters.
*/
template<class NextLayer>
class options_set
{
// workaround for std::function bug in msvc
struct callable
{
virtual ~callable() = default;
virtual void operator()(
beast::websocket::stream<NextLayer>&) = 0;
};
template<class T>
class callable_impl : public callable
{
T t_;
public:
template<class U>
callable_impl(U&& u)
: t_(std::forward<U>(u))
{
}
void
operator()(beast::websocket::stream<NextLayer>& ws)
{
t_(ws);
}
};
template<class Opt>
class lambda
{
Opt opt_;
public:
lambda(lambda&&) = default;
lambda(lambda const&) = default;
lambda(Opt const& opt)
: opt_(opt)
{
}
void
operator()(beast::websocket::stream<NextLayer>& ws) const
{
ws.set_option(opt_);
}
};
std::unordered_map<std::type_index,
std::unique_ptr<callable>> list_;
public:
template<class Opt>
void
set_option(Opt const& opt)
{
std::unique_ptr<callable> p;
p.reset(new callable_impl<lambda<Opt>>{opt});
list_[std::type_index{
typeid(Opt)}] = std::move(p);
}
void
set_options(beast::websocket::stream<NextLayer>& ws)
{
for(auto const& op : list_)
(*op.second)(ws);
}
};
std::ostream* log_;
boost::asio::io_service ios_;
socket_type sock_;
endpoint_type ep_;
boost::asio::ip::tcp::acceptor acceptor_;
std::vector<std::thread> thread_;
boost::optional<boost::asio::io_service::work> work_;
options_set<socket_type> opts_;
public:
async_echo_server(async_echo_server const&) = delete;
async_echo_server& operator=(async_echo_server const&) = delete;
/** Constructor.
@param log A pointer to a stream to log to, or `nullptr`
to disable logging.
@param threads The number of threads in the io_service.
*/
async_echo_server(std::ostream* log,
std::size_t threads)
: log_(log)
, sock_(ios_)
, acceptor_(ios_)
, work_(ios_)
{
opts_.set_option(
beast::websocket::decorate(identity{}));
thread_.reserve(threads);
for(std::size_t i = 0; i < threads; ++i)
thread_.emplace_back(
[&]{ ios_.run(); });
}
/** Destructor.
*/
~async_echo_server()
{
work_ = boost::none;
error_code ec;
ios_.dispatch(
[&]{ acceptor_.close(ec); });
for(auto& t : thread_)
t.join();
}
/** Return the listening endpoint.
*/
endpoint_type
local_endpoint() const
{
return acceptor_.local_endpoint();
}
/** Set a websocket option.
The option will be applied to all new connections.
@param opt The option to apply.
*/
template<class Opt>
void
set_option(Opt const& opt)
{
opts_.set_option(opt);
}
/** Open a listening port.
@param ep The address and port to bind to.
@param ec Set to the error, if any occurred.
*/
void
open(endpoint_type const& ep, error_code& ec)
{
acceptor_.open(ep.protocol(), ec);
if(ec)
return fail("open", ec);
acceptor_.set_option(
boost::asio::socket_base::reuse_address{true});
acceptor_.bind(ep, ec);
if(ec)
return fail("bind", ec);
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
if(ec)
return fail("listen", ec);
acceptor_.async_accept(sock_, ep_,
std::bind(&async_echo_server::on_accept, this,
beast::asio::placeholders::error));
}
private:
class peer
{
struct data
{
async_echo_server& server;
endpoint_type ep;
int state = 0;
beast::websocket::stream<socket_type> ws;
boost::asio::io_service::strand strand;
beast::websocket::opcode op;
beast::streambuf db;
std::size_t id;
data(async_echo_server& server_,
endpoint_type const& ep_,
socket_type&& sock_)
: server(server_)
, ep(ep_)
, ws(std::move(sock_))
, strand(ws.get_io_service())
, id([]
{
static std::atomic<std::size_t> n{0};
return ++n;
}())
{
}
};
// VFALCO This could be unique_ptr in [Net.TS]
std::shared_ptr<data> d_;
public:
peer(peer&&) = default;
peer(peer const&) = default;
peer& operator=(peer&&) = delete;
peer& operator=(peer const&) = delete;
template<class... Args>
explicit
peer(async_echo_server& server,
endpoint_type const& ep, socket_type&& sock,
Args&&... args)
: d_(std::make_shared<data>(server, ep,
std::forward<socket_type>(sock),
std::forward<Args>(args)...))
{
auto& d = *d_;
d.server.opts_.set_options(d.ws);
run();
}
void run()
{
auto& d = *d_;
d.ws.async_accept(std::move(*this));
}
template<class DynamicBuffer, std::size_t N>
static
bool
match(DynamicBuffer& db, char const(&s)[N])
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
if(db.size() < N-1)
return false;
beast::static_string<N-1> t;
t.resize(N-1);
buffer_copy(buffer(t.data(), t.size()),
db.data());
if(t != s)
return false;
db.consume(N-1);
return true;
}
void operator()(error_code ec, std::size_t)
{
(*this)(ec);
}
void operator()(error_code ec)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
auto& d = *d_;
switch(d.state)
{
// did accept
case 0:
if(ec)
return fail("async_accept", ec);
// start
case 1:
if(ec)
return fail("async_handshake", ec);
d.db.consume(d.db.size());
// read message
d.state = 2;
d.ws.async_read(d.op, d.db,
d.strand.wrap(std::move(*this)));
return;
// got message
case 2:
if(ec == beast::websocket::error::closed)
return;
if(ec)
return fail("async_read", ec);
if(match(d.db, "RAW"))
{
d.state = 1;
boost::asio::async_write(d.ws.next_layer(),
d.db.data(), d.strand.wrap(std::move(*this)));
return;
}
else if(match(d.db, "TEXT"))
{
d.state = 1;
d.ws.set_option(
beast::websocket::message_type{
beast::websocket::opcode::text});
d.ws.async_write(
d.db.data(), d.strand.wrap(std::move(*this)));
return;
}
else if(match(d.db, "PING"))
{
beast::websocket::ping_data payload;
d.db.consume(buffer_copy(
buffer(payload.data(), payload.size()),
d.db.data()));
d.state = 1;
d.ws.async_ping(payload,
d.strand.wrap(std::move(*this)));
return;
}
else if(match(d.db, "CLOSE"))
{
d.state = 1;
d.ws.async_close({},
d.strand.wrap(std::move(*this)));
return;
}
// write message
d.state = 1;
d.ws.set_option(
beast::websocket::message_type(d.op));
d.ws.async_write(d.db.data(),
d.strand.wrap(std::move(*this)));
return;
}
}
private:
void
fail(std::string what, error_code ec)
{
auto& d = *d_;
if(d.server.log_)
if(ec != beast::websocket::error::closed)
d.server.fail("[#" + std::to_string(d.id) +
" " + boost::lexical_cast<std::string>(d.ep) +
"] " + what, ec);
}
};
void
fail(std::string what, error_code ec)
{
if(log_)
{
static std::mutex m;
std::lock_guard<std::mutex> lock{m};
(*log_) << what << ": " <<
ec.message() << std::endl;
}
}
void
on_accept(error_code ec)
{
if(! acceptor_.is_open())
return;
if(ec == boost::asio::error::operation_aborted)
return;
if(ec)
fail("accept", ec);
peer{*this, ep_, std::move(sock_)};
acceptor_.async_accept(sock_, ep_,
std::bind(&async_echo_server::on_accept, this,
beast::asio::placeholders::error));
}
};
} // websocket
#endif

View File

@@ -0,0 +1,372 @@
//
// Copyright (c) 2013-2017 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)
//
#ifndef BEAST_WEBSOCKET_SYNC_ECHO_SERVER_HPP
#define BEAST_WEBSOCKET_SYNC_ECHO_SERVER_HPP
#include <beast/core/placeholders.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/websocket.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <ostream>
#include <string>
#include <thread>
#include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <utility>
namespace websocket {
/** Synchronous WebSocket echo client/server
*/
class sync_echo_server
{
public:
using error_code = beast::error_code;
using endpoint_type = boost::asio::ip::tcp::endpoint;
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
private:
struct identity
{
template<class Body, class Fields>
void
operator()(beast::http::message<
true, Body, Fields>& req) const
{
req.fields.replace("User-Agent", "sync_echo_client");
}
template<class Body, class Fields>
void
operator()(beast::http::message<
false, Body, Fields>& resp) const
{
resp.fields.replace("Server", "sync_echo_server");
}
};
/** A container of type-erased option setters.
*/
template<class NextLayer>
class options_set
{
// workaround for std::function bug in msvc
struct callable
{
virtual ~callable() = default;
virtual void operator()(
beast::websocket::stream<NextLayer>&) = 0;
};
template<class T>
class callable_impl : public callable
{
T t_;
public:
template<class U>
callable_impl(U&& u)
: t_(std::forward<U>(u))
{
}
void
operator()(beast::websocket::stream<NextLayer>& ws)
{
t_(ws);
}
};
template<class Opt>
class lambda
{
Opt opt_;
public:
lambda(lambda&&) = default;
lambda(lambda const&) = default;
lambda(Opt const& opt)
: opt_(opt)
{
}
void
operator()(beast::websocket::stream<NextLayer>& ws) const
{
ws.set_option(opt_);
}
};
std::unordered_map<std::type_index,
std::unique_ptr<callable>> list_;
public:
template<class Opt>
void
set_option(Opt const& opt)
{
std::unique_ptr<callable> p;
p.reset(new callable_impl<lambda<Opt>>{opt});
list_[std::type_index{
typeid(Opt)}] = std::move(p);
}
void
set_options(beast::websocket::stream<NextLayer>& ws)
{
for(auto const& op : list_)
(*op.second)(ws);
}
};
std::ostream* log_;
boost::asio::io_service ios_;
socket_type sock_;
endpoint_type ep_;
boost::asio::ip::tcp::acceptor acceptor_;
std::thread thread_;
options_set<socket_type> opts_;
public:
/** Constructor.
@param log A pointer to a stream to log to, or `nullptr`
to disable logging.
*/
sync_echo_server(std::ostream* log)
: log_(log)
, sock_(ios_)
, acceptor_(ios_)
{
opts_.set_option(
beast::websocket::decorate(identity{}));
}
/** Destructor.
*/
~sync_echo_server()
{
if(thread_.joinable())
{
error_code ec;
ios_.dispatch(
[&]{ acceptor_.close(ec); });
thread_.join();
}
}
/** Return the listening endpoint.
*/
endpoint_type
local_endpoint() const
{
return acceptor_.local_endpoint();
}
/** Set a websocket option.
The option will be applied to all new connections.
@param opt The option to apply.
*/
template<class Opt>
void
set_option(Opt const& opt)
{
opts_.set_option(opt);
}
/** Open a listening port.
@param ep The address and port to bind to.
@param ec Set to the error, if any occurred.
*/
void
open(endpoint_type const& ep, error_code& ec)
{
acceptor_.open(ep.protocol(), ec);
if(ec)
return fail("open", ec);
acceptor_.set_option(
boost::asio::socket_base::reuse_address{true});
acceptor_.bind(ep, ec);
if(ec)
return fail("bind", ec);
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
if(ec)
return fail("listen", ec);
acceptor_.async_accept(sock_, ep_,
std::bind(&sync_echo_server::on_accept, this,
beast::asio::placeholders::error));
thread_ = std::thread{[&]{ ios_.run(); }};
}
private:
void
fail(std::string what, error_code ec)
{
if(log_)
{
static std::mutex m;
std::lock_guard<std::mutex> lock{m};
(*log_) << what << ": " <<
ec.message() << std::endl;
}
}
void
fail(std::string what, error_code ec,
int id, endpoint_type const& ep)
{
if(log_)
if(ec != beast::websocket::error::closed)
fail("[#" + std::to_string(id) + " " +
boost::lexical_cast<std::string>(ep) +
"] " + what, ec);
}
void
on_accept(error_code ec)
{
if(ec == boost::asio::error::operation_aborted)
return;
if(ec)
return fail("accept", ec);
struct lambda
{
std::size_t id;
endpoint_type ep;
sync_echo_server& self;
boost::asio::io_service::work work;
// Must be destroyed before work otherwise the
// io_service could be destroyed before the socket.
socket_type sock;
lambda(sync_echo_server& self_,
endpoint_type const& ep_,
socket_type&& sock_)
: id([]
{
static std::atomic<std::size_t> n{0};
return ++n;
}())
, ep(ep_)
, self(self_)
, work(sock_.get_io_service())
, sock(std::move(sock_))
{
}
void operator()()
{
self.do_peer(id, ep, std::move(sock));
}
};
std::thread{lambda{*this, ep_, std::move(sock_)}}.detach();
acceptor_.async_accept(sock_, ep_,
std::bind(&sync_echo_server::on_accept, this,
beast::asio::placeholders::error));
}
template<class DynamicBuffer, std::size_t N>
static
bool
match(DynamicBuffer& db, char const(&s)[N])
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
if(db.size() < N-1)
return false;
beast::static_string<N-1> t;
t.resize(N-1);
buffer_copy(buffer(t.data(), t.size()),
db.data());
if(t != s)
return false;
db.consume(N-1);
return true;
}
void
do_peer(std::size_t id,
endpoint_type const& ep, socket_type&& sock)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
beast::websocket::stream<
socket_type> ws{std::move(sock)};
opts_.set_options(ws);
error_code ec;
ws.accept(ec);
if(ec)
{
fail("accept", ec, id, ep);
return;
}
for(;;)
{
beast::websocket::opcode op;
beast::streambuf sb;
ws.read(op, sb, ec);
if(ec)
{
auto const s = ec.message();
break;
}
ws.set_option(beast::websocket::message_type{op});
if(match(sb, "RAW"))
{
boost::asio::write(
ws.next_layer(), sb.data(), ec);
}
else if(match(sb, "TEXT"))
{
ws.set_option(
beast::websocket::message_type{
beast::websocket::opcode::text});
ws.write(sb.data(), ec);
}
else if(match(sb, "PING"))
{
beast::websocket::ping_data payload;
sb.consume(buffer_copy(
buffer(payload.data(), payload.size()),
sb.data()));
ws.ping(payload, ec);
}
else if(match(sb, "CLOSE"))
{
ws.close({}, ec);
}
else
{
ws.write(sb.data(), ec);
}
if(ec)
break;
}
if(ec && ec != beast::websocket::error::closed)
{
fail("read", ec, id, ep);
}
}
};
} // websocket
#endif

9
test/zlib.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/zlib.hpp>

26
test/zlib/CMakeLists.txt Normal file
View File

@@ -0,0 +1,26 @@
# Part of Beast
GroupSources(extras/beast extras)
GroupSources(include/beast beast)
GroupSources(test/zlib "/")
if (MSVC)
set_source_files_properties (${ZLIB_SOURCES} PROPERTIES COMPILE_FLAGS "/wd4127 /wd4131 /wd4244")
endif()
add_executable (zlib-tests
${BEAST_INCLUDES}
${EXTRAS_INCLUDES}
${ZLIB_SOURCES}
../../extras/beast/unit_test/main.cpp
ztest.hpp
deflate_stream.cpp
error.cpp
inflate_stream.cpp
)
if (NOT WIN32)
target_link_libraries(zlib-tests ${Boost_LIBRARIES} Threads::Threads)
else()
target_link_libraries(zlib-tests ${Boost_LIBRARIES})
endif()

View File

@@ -0,0 +1,336 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/zlib/deflate_stream.hpp>
#include "ztest.hpp"
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace zlib {
class deflate_stream_test : public beast::unit_test::suite
{
public:
using self = deflate_stream_test;
typedef void(self::*pmf_t)(
int level, int windowBits, int strategy,
std::string const&);
static
Strategy
toStrategy(int strategy)
{
switch(strategy)
{
default:
case 0: return Strategy::normal;
case 1: return Strategy::filtered;
case 2: return Strategy::huffman;
case 3: return Strategy::rle;
case 4: return Strategy::fixed;
}
}
void
doDeflate1_zlib(
int level, int windowBits, int strategy,
std::string const& check)
{
int result;
std::string out;
::z_stream zs;
std::memset(&zs, 0, sizeof(zs));
result = deflateInit2(&zs,
level,
Z_DEFLATED,
-windowBits,
8,
strategy);
if(! BEAST_EXPECT(result == Z_OK))
goto err;
out.resize(deflateBound(&zs,
static_cast<uLong>(check.size())));
zs.next_in = (Bytef*)check.data();
zs.avail_in = static_cast<uInt>(check.size());
zs.next_out = (Bytef*)out.data();
zs.avail_out = static_cast<uInt>(out.size());
{
bool progress = true;
for(;;)
{
result = deflate(&zs, Z_FULL_FLUSH);
if( result == Z_BUF_ERROR ||
result == Z_STREAM_END) // per zlib FAQ
goto fin;
if(! BEAST_EXPECT(progress))
goto err;
progress = false;
}
}
fin:
out.resize(zs.total_out);
{
z_inflator zi;
auto const s = zi(out);
BEAST_EXPECT(s == check);
}
err:
deflateEnd(&zs);
}
void
doDeflate1_beast(
int level, int windowBits, int strategy,
std::string const& check)
{
std::string out;
z_params zs;
deflate_stream ds;
ds.reset(
level,
windowBits,
8,
toStrategy(strategy));
out.resize(ds.upper_bound(
static_cast<uLong>(check.size())));
zs.next_in = (Bytef*)check.data();
zs.avail_in = static_cast<uInt>(check.size());
zs.next_out = (Bytef*)out.data();
zs.avail_out = static_cast<uInt>(out.size());
{
bool progress = true;
for(;;)
{
error_code ec;
ds.write(zs, Flush::full, ec);
if( ec == error::need_buffers ||
ec == error::end_of_stream) // per zlib FAQ
goto fin;
if(! BEAST_EXPECTS(! ec, ec.message()))
goto err;
if(! BEAST_EXPECT(progress))
goto err;
progress = false;
}
}
fin:
out.resize(zs.total_out);
{
z_inflator zi;
auto const s = zi(out);
BEAST_EXPECT(s == check);
}
err:
;
}
//--------------------------------------------------------------------------
void
doDeflate2_zlib(
int level, int windowBits, int strategy,
std::string const& check)
{
for(std::size_t i = 1; i < check.size(); ++i)
{
for(std::size_t j = 1;; ++j)
{
int result;
::z_stream zs;
std::memset(&zs, 0, sizeof(zs));
result = deflateInit2(&zs,
level,
Z_DEFLATED,
-windowBits,
8,
strategy);
if(! BEAST_EXPECT(result == Z_OK))
continue;
std::string out;
out.resize(deflateBound(&zs,
static_cast<uLong>(check.size())));
if(j >= out.size())
{
deflateEnd(&zs);
break;
}
zs.next_in = (Bytef*)check.data();
zs.avail_in = static_cast<uInt>(i);
zs.next_out = (Bytef*)out.data();
zs.avail_out = static_cast<uInt>(j);
bool bi = false;
bool bo = false;
for(;;)
{
int flush = bi ? Z_FULL_FLUSH : Z_NO_FLUSH;
result = deflate(&zs, flush);
if( result == Z_BUF_ERROR ||
result == Z_STREAM_END) // per zlib FAQ
goto fin;
if(! BEAST_EXPECT(result == Z_OK))
goto err;
if(zs.avail_in == 0 && ! bi)
{
bi = true;
zs.avail_in =
static_cast<uInt>(check.size() - i);
}
if(zs.avail_out == 0 && ! bo)
{
bo = true;
zs.avail_out =
static_cast<uInt>(out.size() - j);
}
}
fin:
out.resize(zs.total_out);
{
z_inflator zi;
auto const s = zi(out);
BEAST_EXPECT(s == check);
}
err:
deflateEnd(&zs);
}
}
}
void
doDeflate2_beast(
int level, int windowBits, int strategy,
std::string const& check)
{
for(std::size_t i = 1; i < check.size(); ++i)
{
for(std::size_t j = 1;; ++j)
{
z_params zs;
deflate_stream ds;
ds.reset(
level,
windowBits,
8,
toStrategy(strategy));
std::string out;
out.resize(ds.upper_bound(
static_cast<uLong>(check.size())));
if(j >= out.size())
break;
zs.next_in = (Bytef*)check.data();
zs.avail_in = static_cast<uInt>(i);
zs.next_out = (Bytef*)out.data();
zs.avail_out = static_cast<uInt>(j);
bool bi = false;
bool bo = false;
for(;;)
{
error_code ec;
ds.write(zs,
bi ? Flush::full : Flush::none, ec);
if( ec == error::need_buffers ||
ec == error::end_of_stream) // per zlib FAQ
goto fin;
if(! BEAST_EXPECTS(! ec, ec.message()))
goto err;
if(zs.avail_in == 0 && ! bi)
{
bi = true;
zs.avail_in =
static_cast<uInt>(check.size() - i);
}
if(zs.avail_out == 0 && ! bo)
{
bo = true;
zs.avail_out =
static_cast<uInt>(out.size() - j);
}
}
fin:
out.resize(zs.total_out);
{
z_inflator zi;
auto const s = zi(out);
BEAST_EXPECT(s == check);
}
err:
;
}
}
}
//--------------------------------------------------------------------------
void
doMatrix(std::string const& label,
std::string const& check, pmf_t pmf)
{
using namespace std::chrono;
using clock_type = steady_clock;
auto const when = clock_type::now();
for(int level = 0; level <= 9; ++level)
{
for(int windowBits = 8; windowBits <= 9; ++windowBits)
{
for(int strategy = 0; strategy <= 4; ++strategy)
{
(this->*pmf)(
level, windowBits, strategy, check);
}
}
}
auto const elapsed = clock_type::now() - when;
log <<
label << ": " <<
duration_cast<
milliseconds>(elapsed).count() << "ms\n";
log.flush();
}
void
testDeflate()
{
doMatrix("1.beast ", "Hello, world!", &self::doDeflate1_beast);
doMatrix("1.zlib ", "Hello, world!", &self::doDeflate1_zlib);
doMatrix("2.beast ", "Hello, world!", &self::doDeflate2_beast);
doMatrix("2.zlib ", "Hello, world!", &self::doDeflate2_zlib);
{
auto const s = corpus1(56);
doMatrix("3.beast ", s, &self::doDeflate2_beast);
doMatrix("3.zlib ", s, &self::doDeflate2_zlib);
}
{
auto const s = corpus1(512 * 1024);
doMatrix("4.beast ", s, &self::doDeflate1_beast);
doMatrix("4.zlib ", s, &self::doDeflate1_zlib);
}
}
void
run() override
{
log <<
"sizeof(deflate_stream) == " <<
sizeof(deflate_stream) << std::endl;
testDeflate();
}
};
BEAST_DEFINE_TESTSUITE(deflate_stream,core,beast);
} // zlib
} // beast

61
test/zlib/error.cpp Normal file
View File

@@ -0,0 +1,61 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/zlib/error.hpp>
#include <beast/unit_test/suite.hpp>
#include <memory>
namespace beast {
namespace zlib {
class error_test : public unit_test::suite
{
public:
void check(char const* name, error ev)
{
auto const ec = make_error_code(ev);
BEAST_EXPECT(std::string{ec.category().name()} == name);
BEAST_EXPECT(! ec.message().empty());
BEAST_EXPECT(std::addressof(ec.category()) ==
std::addressof(detail::get_error_category()));
BEAST_EXPECT(detail::get_error_category().equivalent(
static_cast<std::underlying_type<error>::type>(ev),
ec.category().default_error_condition(
static_cast<std::underlying_type<error>::type>(ev))));
BEAST_EXPECT(detail::get_error_category().equivalent(
ec, static_cast<std::underlying_type<error>::type>(ev)));
}
void run() override
{
check("zlib", error::need_buffers);
check("zlib", error::end_of_stream);
check("zlib", error::stream_error);
check("zlib", error::invalid_block_type);
check("zlib", error::invalid_stored_length);
check("zlib", error::too_many_symbols);
check("zlib", error::invalid_code_lenths);
check("zlib", error::invalid_bit_length_repeat);
check("zlib", error::missing_eob);
check("zlib", error::invalid_literal_length);
check("zlib", error::invalid_distance_code);
check("zlib", error::invalid_distance);
check("zlib", error::over_subscribed_length);
check("zlib", error::incomplete_length_set);
check("zlib", error::general);
}
};
BEAST_DEFINE_TESTSUITE(error,zlib,beast);
} // zlib
} // beast

View File

@@ -0,0 +1,412 @@
//
// Copyright (c) 2013-2017 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)
//
// Test that header file is self-contained.
#include <beast/zlib/inflate_stream.hpp>
#include "ztest.hpp"
#include <beast/unit_test/suite.hpp>
#include <chrono>
#include <random>
namespace beast {
namespace zlib {
class inflate_stream_test : public beast::unit_test::suite
{
public:
//--------------------------------------------------------------------------
enum Split
{
once,
half,
full
};
class Beast
{
Split in_;
Split check_;
Flush flush_;
public:
Beast(Split in, Split check, Flush flush = Flush::sync)
: in_(in)
, check_(check)
, flush_(flush)
{
}
void
operator()(
int window,
std::string const& in,
std::string const& check,
unit_test::suite& suite) const
{
auto const f =
[&](std::size_t i, std::size_t j)
{
std::string out(check.size(), 0);
z_params zs;
zs.next_in = in.data();
zs.next_out = &out[0];
zs.avail_in = i;
zs.avail_out = j;
inflate_stream is;
is.reset(window);
bool bi = ! (i < in.size());
bool bo = ! (j < check.size());
for(;;)
{
error_code ec;
is.write(zs, flush_, ec);
if( ec == error::need_buffers ||
ec == error::end_of_stream)
{
out.resize(zs.total_out);
suite.expect(out == check, __FILE__, __LINE__);
break;
}
if(ec)
{
suite.fail(ec.message(), __FILE__, __LINE__);
break;
}
if(zs.avail_in == 0 && ! bi)
{
bi = true;
zs.avail_in = in.size() - i;
}
if(zs.avail_out == 0 && ! bo)
{
bo = true;
zs.avail_out = check.size() - j;
}
}
};
std::size_t i0, i1;
std::size_t j0, j1;
switch(in_)
{
default:
case once: i0 = in.size(); i1 = i0; break;
case half: i0 = in.size() / 2; i1 = i0; break;
case full: i0 = 1; i1 = in.size(); break;
}
switch(check_)
{
default:
case once: j0 = check.size(); j1 = j0; break;
case half: j0 = check.size() / 2; j1 = j0; break;
case full: j0 = 1; j1 = check.size(); break;
}
for(std::size_t i = i0; i <= i1; ++i)
for(std::size_t j = j0; j <= j1; ++j)
f(i, j);
}
};
class ZLib
{
Split in_;
Split check_;
int flush_;
public:
ZLib(Split in, Split check, int flush = Z_SYNC_FLUSH)
: in_(in)
, check_(check)
, flush_(flush)
{
}
void
operator()(
int window,
std::string const& in,
std::string const& check,
unit_test::suite& suite) const
{
auto const f =
[&](std::size_t i, std::size_t j)
{
int result;
std::string out(check.size(), 0);
::z_stream zs;
memset(&zs, 0, sizeof(zs));
result = inflateInit2(&zs, -window);
if(result != Z_OK)
{
suite.fail("! Z_OK", __FILE__, __LINE__);
return;
}
zs.next_in = (Bytef*)in.data();
zs.next_out = (Bytef*)out.data();
zs.avail_in = static_cast<uInt>(i);
zs.avail_out = static_cast<uInt>(j);
bool bi = ! (i < in.size());
bool bo = ! (j < check.size());
for(;;)
{
result = inflate(&zs, flush_);
if( result == Z_BUF_ERROR ||
result == Z_STREAM_END) // per zlib FAQ
{
out.resize(zs.total_out);
suite.expect(out == check, __FILE__, __LINE__);
break;
}
if(result != Z_OK)
{
suite.fail("! Z_OK", __FILE__, __LINE__);
break;
}
if(zs.avail_in == 0 && ! bi)
{
bi = true;
zs.avail_in = static_cast<uInt>(in.size() - i);
}
if(zs.avail_out == 0 && ! bo)
{
bo = true;
zs.avail_out = static_cast<uInt>(check.size() - j);
}
}
inflateEnd(&zs);
};
std::size_t i0, i1;
std::size_t j0, j1;
switch(in_)
{
default:
case once: i0 = in.size(); i1 = i0; break;
case half: i0 = in.size() / 2; i1 = i0; break;
case full: i0 = 1; i1 = in.size(); break;
}
switch(check_)
{
default:
case once: j0 = check.size(); j1 = j0; break;
case half: j0 = check.size() / 2; j1 = j0; break;
case full: j0 = 1; j1 = check.size(); break;
}
for(std::size_t i = i0; i <= i1; ++i)
for(std::size_t j = j0; j <= j1; ++j)
f(i, j);
}
};
class Matrix
{
unit_test::suite& suite_;
int level_[2];
int window_[2];
int strategy_[2];
public:
explicit
Matrix(unit_test::suite& suite)
: suite_(suite)
{
level_[0] = 0;
level_[1] = 9;
window_[0] = 8;
window_[1] = 15;
strategy_[0] = 0;
strategy_[1] = 4;
}
void
level(int from, int to)
{
level_[0] = from;
level_[1] = to;
}
void
level(int what)
{
level(what, what);
}
void
window(int from, int to)
{
window_[0] = from;
window_[1] = to;
}
void
window(int what)
{
window(what, what);
}
void
strategy(int from, int to)
{
strategy_[0] = from;
strategy_[1] = to;
}
void
strategy(int what)
{
strategy(what, what);
}
template<class F>
void
operator()(
std::string label,
F const& f,
std::string const& check) const
{
using namespace std::chrono;
using clock_type = steady_clock;
auto const when = clock_type::now();
for(auto level = level_[0];
level <= level_[1]; ++level)
{
for(auto window = window_[0];
window <= window_[1]; ++window)
{
for(auto strategy = strategy_[0];
strategy <= strategy_[1]; ++strategy)
{
z_deflator zd;
zd.level(level);
zd.windowBits(window);
zd.strategy(strategy);
auto const in = zd(check);
f(window, in, check, suite_);
}
}
}
auto const elapsed = clock_type::now() - when;
suite_.log <<
label << ": " <<
duration_cast<
milliseconds>(elapsed).count() << "ms\n";
suite_.log.flush();
}
};
void
testInflate()
{
{
Matrix m{*this};
std::string check =
"{\n \"AutobahnPython/0.6.0\": {\n"
" \"1.1.1\": {\n"
" \"behavior\": \"OK\",\n"
" \"behaviorClose\": \"OK\",\n"
" \"duration\": 2,\n"
" \"remoteCloseCode\": 1000,\n"
" \"reportfile\": \"autobahnpython_0_6_0_case_1_1_1.json\"\n"
;
m("1. beast", Beast{half, half}, check);
m("1. zlib ", ZLib {half, half}, check);
}
{
Matrix m{*this};
auto const check = corpus1(50000);
m("2. beast", Beast{half, half}, check);
m("2. zlib ", ZLib {half, half}, check);
}
{
Matrix m{*this};
auto const check = corpus2(50000);
m("3. beast", Beast{half, half}, check);
m("3. zlib ", ZLib {half, half}, check);
}
{
Matrix m{*this};
auto const check = corpus1(10000);
m.level(6);
m.window(9);
m.strategy(Z_DEFAULT_STRATEGY);
m("4. beast", Beast{once, full}, check);
m("4. zlib ", ZLib {once, full}, check);
}
{
Matrix m{*this};
auto const check = corpus2(10000);
m.level(6);
m.window(9);
m.strategy(Z_DEFAULT_STRATEGY);
m("5. beast", Beast{once, full}, check);
m("5. zlib ", ZLib {once, full}, check);
}
{
Matrix m{*this};
m.level(6);
m.window(9);
auto const check = corpus1(200);
m("6. beast", Beast{full, full}, check);
m("6. zlib ", ZLib {full, full}, check);
}
{
Matrix m{*this};
m.level(6);
m.window(9);
auto const check = corpus2(500);
m("7. beast", Beast{full, full}, check);
m("7. zlib ", ZLib {full, full}, check);
}
{
Matrix m{*this};
auto const check = corpus2(10000);
m.level(6);
m.window(9);
m.strategy(Z_DEFAULT_STRATEGY);
m("8. beast", Beast{full, once, Flush::block}, check);
m("8. zlib ", ZLib {full, once, Z_BLOCK}, check);
}
// VFALCO Fails, but I'm unsure of what the correct
// behavior of Z_TREES/Flush::trees is.
#if 0
{
Matrix m{*this};
auto const check = corpus2(10000);
m.level(6);
m.window(9);
m.strategy(Z_DEFAULT_STRATEGY);
m("9. beast", Beast{full, once, Flush::trees}, check);
m("9. zlib ", ZLib {full, once, Z_TREES}, check);
}
#endif
}
void
run() override
{
log <<
"sizeof(inflate_stream) == " <<
sizeof(inflate_stream) << std::endl;
testInflate();
}
};
BEAST_DEFINE_TESTSUITE(inflate_stream,core,beast);
} // zlib
} // beast

View File

@@ -0,0 +1,249 @@
cmake_minimum_required(VERSION 2.4.4)
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
project(zlib C)
set(VERSION "1.2.8")
option(ASM686 "Enable building i686 assembly implementation")
option(AMD64 "Enable building amd64 assembly implementation")
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers")
set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages")
set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files")
include(CheckTypeSize)
include(CheckFunctionExists)
include(CheckIncludeFile)
include(CheckCSourceCompiles)
enable_testing()
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
check_include_file(stdint.h HAVE_STDINT_H)
check_include_file(stddef.h HAVE_STDDEF_H)
#
# Check to see if we have large file support
#
set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1)
# We add these other definitions here because CheckTypeSize.cmake
# in CMake 2.4.x does not automatically do so and we want
# compatibility with CMake 2.4.x.
if(HAVE_SYS_TYPES_H)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H)
endif()
if(HAVE_STDINT_H)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H)
endif()
if(HAVE_STDDEF_H)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H)
endif()
check_type_size(off64_t OFF64_T)
if(HAVE_OFF64_T)
add_definitions(-D_LARGEFILE64_SOURCE=1)
endif()
set(CMAKE_REQUIRED_DEFINITIONS) # clear variable
#
# Check for fseeko
#
check_function_exists(fseeko HAVE_FSEEKO)
if(NOT HAVE_FSEEKO)
add_definitions(-DNO_FSEEKO)
endif()
#
# Check for unistd.h
#
check_include_file(unistd.h Z_HAVE_UNISTD_H)
if(MSVC)
set(CMAKE_DEBUG_POSTFIX "d")
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
endif()
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
# If we're doing an out of source build and the user has a zconf.h
# in their source tree...
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h)
message(STATUS "Renaming")
message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h")
message(STATUS "to 'zconf.h.included' because this file is included with zlib")
message(STATUS "but CMake generates it automatically in the build directory.")
file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.included)
endif()
endif()
set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein
${ZLIB_PC} @ONLY)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein
${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR})
#============================================================================
# zlib
#============================================================================
set(ZLIB_PUBLIC_HDRS
${CMAKE_CURRENT_BINARY_DIR}/zconf.h
zlib.h
)
set(ZLIB_PRIVATE_HDRS
crc32.h
deflate.h
gzguts.h
inffast.h
inffixed.h
inflate.h
inftrees.h
trees.h
zutil.h
)
set(ZLIB_SRCS
adler32.c
compress.c
crc32.c
deflate.c
gzclose.c
gzlib.c
gzread.c
gzwrite.c
inflate.c
infback.c
inftrees.c
inffast.c
trees.c
uncompr.c
zutil.c
)
if(NOT MINGW)
set(ZLIB_DLL_SRCS
win32/zlib1.rc # If present will override custom build rule below.
)
endif()
if(CMAKE_COMPILER_IS_GNUCC)
if(ASM686)
set(ZLIB_ASMS contrib/asm686/match.S)
elseif (AMD64)
set(ZLIB_ASMS contrib/amd64/amd64-match.S)
endif ()
if(ZLIB_ASMS)
add_definitions(-DASMV)
set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE)
endif()
endif()
if(MSVC)
if(ASM686)
ENABLE_LANGUAGE(ASM_MASM)
set(ZLIB_ASMS
contrib/masmx86/inffas32.asm
contrib/masmx86/match686.asm
)
elseif (AMD64)
ENABLE_LANGUAGE(ASM_MASM)
set(ZLIB_ASMS
contrib/masmx64/gvmat64.asm
contrib/masmx64/inffasx64.asm
)
endif()
if(ZLIB_ASMS)
add_definitions(-DASMV -DASMINF)
endif()
endif()
# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents)
string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*"
"\\1" ZLIB_FULL_VERSION ${_zlib_h_contents})
if(MINGW)
# This gets us DLL resource information when compiling on MinGW.
if(NOT CMAKE_RC_COMPILER)
set(CMAKE_RC_COMPILER windres.exe)
endif()
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj
COMMAND ${CMAKE_RC_COMPILER}
-D GCC_WINDRES
-I ${CMAKE_CURRENT_SOURCE_DIR}
-I ${CMAKE_CURRENT_BINARY_DIR}
-o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj
-i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc)
set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj)
endif(MINGW)
add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
set_target_properties(zlib PROPERTIES SOVERSION 1)
if(NOT CYGWIN)
# This property causes shared libraries on Linux to have the full version
# encoded into their final filename. We disable this on Cygwin because
# it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll
# seems to be the default.
#
# This has no effect with MSVC, on that platform the version info for
# the DLL comes from the resource file win32/zlib1.rc
set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION})
endif()
if(UNIX)
# On unix-like platforms the library is almost always called libz
set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z)
if(NOT APPLE)
set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"")
endif()
elseif(BUILD_SHARED_LIBS AND WIN32)
# Creates zlib1.dll when building shared library version
set_target_properties(zlib PROPERTIES SUFFIX "1.dll")
endif()
if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL )
install(TARGETS zlib zlibstatic
RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
LIBRARY DESTINATION "${INSTALL_LIB_DIR}" )
endif()
if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL )
install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION "${INSTALL_INC_DIR}")
endif()
if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL )
install(FILES zlib.3 DESTINATION "${INSTALL_MAN_DIR}/man3")
endif()
if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL )
install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}")
endif()
#============================================================================
# Example binaries
#============================================================================
add_executable(example test/example.c)
target_link_libraries(example zlib)
add_test(example example)
add_executable(minigzip test/minigzip.c)
target_link_libraries(minigzip zlib)
if(HAVE_OFF64_T)
add_executable(example64 test/example.c)
target_link_libraries(example64 zlib)
set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64")
add_test(example64 example64)
add_executable(minigzip64 test/minigzip.c)
target_link_libraries(minigzip64 zlib)
set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64")
endif()

File diff suppressed because it is too large Load Diff

368
test/zlib/zlib-1.2.8/FAQ Normal file
View File

@@ -0,0 +1,368 @@
Frequently Asked Questions about zlib
If your question is not there, please check the zlib home page
http://zlib.net/ which may have more recent information.
The lastest zlib FAQ is at http://zlib.net/zlib_faq.html
1. Is zlib Y2K-compliant?
Yes. zlib doesn't handle dates.
2. Where can I get a Windows DLL version?
The zlib sources can be compiled without change to produce a DLL. See the
file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the
precompiled DLL are found in the zlib web site at http://zlib.net/ .
3. Where can I get a Visual Basic interface to zlib?
See
* http://marknelson.us/1997/01/01/zlib-engine/
* win32/DLL_FAQ.txt in the zlib distribution
4. compress() returns Z_BUF_ERROR.
Make sure that before the call of compress(), the length of the compressed
buffer is equal to the available size of the compressed buffer and not
zero. For Visual Basic, check that this parameter is passed by reference
("as any"), not by value ("as long").
5. deflate() or inflate() returns Z_BUF_ERROR.
Before making the call, make sure that avail_in and avail_out are not zero.
When setting the parameter flush equal to Z_FINISH, also make sure that
avail_out is big enough to allow processing all pending input. Note that a
Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be
made with more input or output space. A Z_BUF_ERROR may in fact be
unavoidable depending on how the functions are used, since it is not
possible to tell whether or not there is more output pending when
strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a
heavily annotated example.
6. Where's the zlib documentation (man pages, etc.)?
It's in zlib.h . Examples of zlib usage are in the files test/example.c
and test/minigzip.c, with more in examples/ .
7. Why don't you use GNU autoconf or libtool or ...?
Because we would like to keep zlib as a very small and simple package.
zlib is rather portable and doesn't need much configuration.
8. I found a bug in zlib.
Most of the time, such problems are due to an incorrect usage of zlib.
Please try to reproduce the problem with a small program and send the
corresponding source to us at zlib@gzip.org . Do not send multi-megabyte
data files without prior agreement.
9. Why do I get "undefined reference to gzputc"?
If "make test" produces something like
example.o(.text+0x154): undefined reference to `gzputc'
check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
/usr/X11R6/lib. Remove any old versions, then do "make install".
10. I need a Delphi interface to zlib.
See the contrib/delphi directory in the zlib distribution.
11. Can zlib handle .zip archives?
Not by itself, no. See the directory contrib/minizip in the zlib
distribution.
12. Can zlib handle .Z files?
No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt
the code of uncompress on your own.
13. How can I make a Unix shared library?
By default a shared (and a static) library is built for Unix. So:
make distclean
./configure
make
14. How do I install a shared zlib library on Unix?
After the above, then:
make install
However, many flavors of Unix come with a shared zlib already installed.
Before going to the trouble of compiling a shared version of zlib and
trying to install it, you may want to check if it's already there! If you
can #include <zlib.h>, it's there. The -lz option will probably link to
it. You can check the version at the top of zlib.h or with the
ZLIB_VERSION symbol defined in zlib.h .
15. I have a question about OttoPDF.
We are not the authors of OttoPDF. The real author is on the OttoPDF web
site: Joel Hainley, jhainley@myndkryme.com.
16. Can zlib decode Flate data in an Adobe PDF file?
Yes. See http://www.pdflib.com/ . To modify PDF forms, see
http://sourceforge.net/projects/acroformtool/ .
17. Why am I getting this "register_frame_info not found" error on Solaris?
After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib
generates an error such as:
ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so:
symbol __register_frame_info: referenced symbol not found
The symbol __register_frame_info is not part of zlib, it is generated by
the C compiler (cc or gcc). You must recompile applications using zlib
which have this problem. This problem is specific to Solaris. See
http://www.sunfreeware.com for Solaris versions of zlib and applications
using zlib.
18. Why does gzip give an error on a file I make with compress/deflate?
The compress and deflate functions produce data in the zlib format, which
is different and incompatible with the gzip format. The gz* functions in
zlib on the other hand use the gzip format. Both the zlib and gzip formats
use the same compressed data format internally, but have different headers
and trailers around the compressed data.
19. Ok, so why are there two different formats?
The gzip format was designed to retain the directory information about a
single file, such as the name and last modification date. The zlib format
on the other hand was designed for in-memory and communication channel
applications, and has a much more compact header and trailer and uses a
faster integrity check than gzip.
20. Well that's nice, but how do I make a gzip file in memory?
You can request that deflate write the gzip format instead of the zlib
format using deflateInit2(). You can also request that inflate decode the
gzip format using inflateInit2(). Read zlib.h for more details.
21. Is zlib thread-safe?
Yes. However any library routines that zlib uses and any application-
provided memory allocation routines must also be thread-safe. zlib's gz*
functions use stdio library routines, and most of zlib's functions use the
library memory allocation routines by default. zlib's *Init* functions
allow for the application to provide custom memory allocation routines.
Of course, you should only operate on any given zlib or gzip stream from a
single thread at a time.
22. Can I use zlib in my commercial application?
Yes. Please read the license in zlib.h.
23. Is zlib under the GNU license?
No. Please read the license in zlib.h.
24. The license says that altered source versions must be "plainly marked". So
what exactly do I need to do to meet that requirement?
You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In
particular, the final version number needs to be changed to "f", and an
identification string should be appended to ZLIB_VERSION. Version numbers
x.x.x.f are reserved for modifications to zlib by others than the zlib
maintainers. For example, if the version of the base zlib you are altering
is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also
update the version strings in deflate.c and inftrees.c.
For altered source distributions, you should also note the origin and
nature of the changes in zlib.h, as well as in ChangeLog and README, along
with the dates of the alterations. The origin should include at least your
name (or your company's name), and an email address to contact for help or
issues with the library.
Note that distributing a compiled zlib library along with zlib.h and
zconf.h is also a source distribution, and so you should change
ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
in zlib.h as you would for a full source distribution.
25. Will zlib work on a big-endian or little-endian architecture, and can I
exchange compressed data between them?
Yes and yes.
26. Will zlib work on a 64-bit machine?
Yes. It has been tested on 64-bit machines, and has no dependence on any
data types being limited to 32-bits in length. If you have any
difficulties, please provide a complete problem report to zlib@gzip.org
27. Will zlib decompress data from the PKWare Data Compression Library?
No. The PKWare DCL uses a completely different compressed data format than
does PKZIP and zlib. However, you can look in zlib's contrib/blast
directory for a possible solution to your problem.
28. Can I access data randomly in a compressed stream?
No, not without some preparation. If when compressing you periodically use
Z_FULL_FLUSH, carefully write all the pending data at those points, and
keep an index of those locations, then you can start decompression at those
points. You have to be careful to not use Z_FULL_FLUSH too often, since it
can significantly degrade compression. Alternatively, you can scan a
deflate stream once to generate an index, and then use that index for
random access. See examples/zran.c .
29. Does zlib work on MVS, OS/390, CICS, etc.?
It has in the past, but we have not heard of any recent evidence. There
were working ports of zlib 1.1.4 to MVS, but those links no longer work.
If you know of recent, successful applications of zlib on these operating
systems, please let us know. Thanks.
30. Is there some simpler, easier to read version of inflate I can look at to
understand the deflate format?
First off, you should read RFC 1951. Second, yes. Look in zlib's
contrib/puff directory.
31. Does zlib infringe on any patents?
As far as we know, no. In fact, that was originally the whole point behind
zlib. Look here for some more information:
http://www.gzip.org/#faq11
32. Can zlib work with greater than 4 GB of data?
Yes. inflate() and deflate() will process any amount of data correctly.
Each call of inflate() or deflate() is limited to input and output chunks
of the maximum value that can be stored in the compiler's "unsigned int"
type, but there is no limit to the number of chunks. Note however that the
strm.total_in and strm_total_out counters may be limited to 4 GB. These
counters are provided as a convenience and are not used internally by
inflate() or deflate(). The application can easily set up its own counters
updated after each call of inflate() or deflate() to count beyond 4 GB.
compress() and uncompress() may be limited to 4 GB, since they operate in a
single call. gzseek() and gztell() may be limited to 4 GB depending on how
zlib is compiled. See the zlibCompileFlags() function in zlib.h.
The word "may" appears several times above since there is a 4 GB limit only
if the compiler's "long" type is 32 bits. If the compiler's "long" type is
64 bits, then the limit is 16 exabytes.
33. Does zlib have any security vulnerabilities?
The only one that we are aware of is potentially in gzprintf(). If zlib is
compiled to use sprintf() or vsprintf(), then there is no protection
against a buffer overflow of an 8K string space (or other value as set by
gzbuffer()), other than the caller of gzprintf() assuring that the output
will not exceed 8K. On the other hand, if zlib is compiled to use
snprintf() or vsnprintf(), which should normally be the case, then there is
no vulnerability. The ./configure script will display warnings if an
insecure variation of sprintf() will be used by gzprintf(). Also the
zlibCompileFlags() function will return information on what variant of
sprintf() is used by gzprintf().
If you don't have snprintf() or vsnprintf() and would like one, you can
find a portable implementation here:
http://www.ijs.si/software/snprintf/
Note that you should be using the most recent version of zlib. Versions
1.1.3 and before were subject to a double-free vulnerability, and versions
1.2.1 and 1.2.2 were subject to an access exception when decompressing
invalid compressed data.
34. Is there a Java version of zlib?
Probably what you want is to use zlib in Java. zlib is already included
as part of the Java SDK in the java.util.zip package. If you really want
a version of zlib written in the Java language, look on the zlib home
page for links: http://zlib.net/ .
35. I get this or that compiler or source-code scanner warning when I crank it
up to maximally-pedantic. Can't you guys write proper code?
Many years ago, we gave up attempting to avoid warnings on every compiler
in the universe. It just got to be a waste of time, and some compilers
were downright silly as well as contradicted each other. So now, we simply
make sure that the code always works.
36. Valgrind (or some similar memory access checker) says that deflate is
performing a conditional jump that depends on an uninitialized value.
Isn't that a bug?
No. That is intentional for performance reasons, and the output of deflate
is not affected. This only started showing up recently since zlib 1.2.x
uses malloc() by default for allocations, whereas earlier versions used
calloc(), which zeros out the allocated memory. Even though the code was
correct, versions 1.2.4 and later was changed to not stimulate these
checkers.
37. Will zlib read the (insert any ancient or arcane format here) compressed
data format?
Probably not. Look in the comp.compression FAQ for pointers to various
formats and associated software.
38. How can I encrypt/decrypt zip files with zlib?
zlib doesn't support encryption. The original PKZIP encryption is very
weak and can be broken with freely available programs. To get strong
encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib
compression. For PKZIP compatible "encryption", look at
http://www.info-zip.org/
39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
"gzip" is the gzip format, and "deflate" is the zlib format. They should
probably have called the second one "zlib" instead to avoid confusion with
the raw deflate compressed data format. While the HTTP 1.1 RFC 2616
correctly points to the zlib specification in RFC 1950 for the "deflate"
transfer encoding, there have been reports of servers and browsers that
incorrectly produce or expect raw deflate data per the deflate
specification in RFC 1951, most notably Microsoft. So even though the
"deflate" transfer encoding using the zlib format would be the more
efficient approach (and in fact exactly what the zlib format was designed
for), using the "gzip" transfer encoding is probably more reliable due to
an unfortunate choice of name on the part of the HTTP 1.1 authors.
Bottom line: use the gzip format for HTTP 1.1 encoding.
40. Does zlib support the new "Deflate64" format introduced by PKWare?
No. PKWare has apparently decided to keep that format proprietary, since
they have not documented it as they have previous compression formats. In
any case, the compression improvements are so modest compared to other more
modern approaches, that it's not worth the effort to implement.
41. I'm having a problem with the zip functions in zlib, can you help?
There are no zip functions in zlib. You are probably using minizip by
Giles Vollant, which is found in the contrib directory of zlib. It is not
part of zlib. In fact none of the stuff in contrib is part of zlib. The
files in there are not supported by the zlib authors. You need to contact
the authors of the respective contribution for help.
42. The match.asm code in contrib is under the GNU General Public License.
Since it's part of zlib, doesn't that mean that all of zlib falls under the
GNU GPL?
No. The files in contrib are not part of zlib. They were contributed by
other authors and are provided as a convenience to the user within the zlib
distribution. Each item in contrib has its own license.
43. Is zlib subject to export controls? What is its ECCN?
zlib is not subject to export controls, and so is classified as EAR99.
44. Can you please sign these lengthy legal documents and fax them back to us
so that we can use your software in our product?
No. Go away. Shoo.

View File

@@ -0,0 +1,68 @@
CMakeLists.txt cmake build file
ChangeLog history of changes
FAQ Frequently Asked Questions about zlib
INDEX this file
Makefile dummy Makefile that tells you to ./configure
Makefile.in template for Unix Makefile
README guess what
configure configure script for Unix
make_vms.com makefile for VMS
test/example.c zlib usages examples for build testing
test/minigzip.c minimal gzip-like functionality for build testing
test/infcover.c inf*.c code coverage for build coverage testing
treebuild.xml XML description of source file dependencies
zconf.h.cmakein zconf.h template for cmake
zconf.h.in zconf.h template for configure
zlib.3 Man page for zlib
zlib.3.pdf Man page in PDF format
zlib.map Linux symbol information
zlib.pc.in Template for pkg-config descriptor
zlib.pc.cmakein zlib.pc template for cmake
zlib2ansi perl script to convert source files for C++ compilation
amiga/ makefiles for Amiga SAS C
as400/ makefiles for AS/400
doc/ documentation for formats and algorithms
msdos/ makefiles for MSDOS
nintendods/ makefile for Nintendo DS
old/ makefiles for various architectures and zlib documentation
files that have not yet been updated for zlib 1.2.x
qnx/ makefiles for QNX
watcom/ makefiles for OpenWatcom
win32/ makefiles for Windows
zlib public header files (required for library use):
zconf.h
zlib.h
private source files used to build the zlib library:
adler32.c
compress.c
crc32.c
crc32.h
deflate.c
deflate.h
gzclose.c
gzguts.h
gzlib.c
gzread.c
gzwrite.c
infback.c
inffast.c
inffast.h
inffixed.h
inflate.c
inflate.h
inftrees.c
inftrees.h
trees.c
trees.h
uncompr.c
zutil.c
zutil.h
source files for sample programs
See examples/README.examples
unsupported contributions by third parties
See contrib/README.contrib

View File

@@ -0,0 +1,5 @@
all:
-@echo "Please use ./configure first. Thank you."
distclean:
make -f Makefile.in distclean

View File

@@ -0,0 +1,288 @@
# Makefile for zlib
# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler
# For conditions of distribution and use, see copyright notice in zlib.h
# To compile and test, type:
# ./configure; make test
# Normally configure builds both a static and a shared library.
# If you want to build just a static library, use: ./configure --static
# To use the asm code, type:
# cp contrib/asm?86/match.S ./match.S
# make LOC=-DASMV OBJA=match.o
# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
# make install
# To install in $HOME instead of /usr/local, use:
# make install prefix=$HOME
CC=cc
CFLAGS=-O
#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
#CFLAGS=-g -DDEBUG
#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
# -Wstrict-prototypes -Wmissing-prototypes
SFLAGS=-O
LDFLAGS=
TEST_LDFLAGS=-L. libz.a
LDSHARED=$(CC)
CPP=$(CC) -E
STATICLIB=libz.a
SHAREDLIB=libz.so
SHAREDLIBV=libz.so.1.2.8
SHAREDLIBM=libz.so.1
LIBS=$(STATICLIB) $(SHAREDLIBV)
AR=ar
ARFLAGS=rc
RANLIB=ranlib
LDCONFIG=ldconfig
LDSHAREDLIBC=-lc
TAR=tar
SHELL=/bin/sh
EXE=
prefix = /usr/local
exec_prefix = ${prefix}
libdir = ${exec_prefix}/lib
sharedlibdir = ${libdir}
includedir = ${prefix}/include
mandir = ${prefix}/share/man
man3dir = ${mandir}/man3
pkgconfigdir = ${libdir}/pkgconfig
OBJZ = adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o
OBJG = compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o
OBJC = $(OBJZ) $(OBJG)
PIC_OBJZ = adler32.lo crc32.lo deflate.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo zutil.lo
PIC_OBJG = compress.lo uncompr.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo
PIC_OBJC = $(PIC_OBJZ) $(PIC_OBJG)
# to use the asm code: make OBJA=match.o, PIC_OBJA=match.lo
OBJA =
PIC_OBJA =
OBJS = $(OBJC) $(OBJA)
PIC_OBJS = $(PIC_OBJC) $(PIC_OBJA)
all: static shared
static: example$(EXE) minigzip$(EXE)
shared: examplesh$(EXE) minigzipsh$(EXE)
all64: example64$(EXE) minigzip64$(EXE)
check: test
test: all teststatic testshared
teststatic: static
@TMPST=tmpst_$$; \
if echo hello world | ./minigzip | ./minigzip -d && ./example $$TMPST ; then \
echo ' *** zlib test OK ***'; \
else \
echo ' *** zlib test FAILED ***'; false; \
fi; \
rm -f $$TMPST
testshared: shared
@LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \
DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \
SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \
TMPSH=tmpsh_$$; \
if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh $$TMPSH; then \
echo ' *** zlib shared test OK ***'; \
else \
echo ' *** zlib shared test FAILED ***'; false; \
fi; \
rm -f $$TMPSH
test64: all64
@TMP64=tmp64_$$; \
if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64 $$TMP64; then \
echo ' *** zlib 64-bit test OK ***'; \
else \
echo ' *** zlib 64-bit test FAILED ***'; false; \
fi; \
rm -f $$TMP64
infcover.o: test/infcover.c zlib.h zconf.h
$(CC) $(CFLAGS) -I. -c -o $@ test/infcover.c
infcover: infcover.o libz.a
$(CC) $(CFLAGS) -o $@ infcover.o libz.a
cover: infcover
rm -f *.gcda
./infcover
gcov inf*.c
libz.a: $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
-@ ($(RANLIB) $@ || true) >/dev/null 2>&1
match.o: match.S
$(CPP) match.S > _match.s
$(CC) -c _match.s
mv _match.o match.o
rm -f _match.s
match.lo: match.S
$(CPP) match.S > _match.s
$(CC) -c -fPIC _match.s
mv _match.o match.lo
rm -f _match.s
example.o: test/example.c zlib.h zconf.h
$(CC) $(CFLAGS) -I. -c -o $@ test/example.c
minigzip.o: test/minigzip.c zlib.h zconf.h
$(CC) $(CFLAGS) -I. -c -o $@ test/minigzip.c
example64.o: test/example.c zlib.h zconf.h
$(CC) $(CFLAGS) -I. -D_FILE_OFFSET_BITS=64 -c -o $@ test/example.c
minigzip64.o: test/minigzip.c zlib.h zconf.h
$(CC) $(CFLAGS) -I. -D_FILE_OFFSET_BITS=64 -c -o $@ test/minigzip.c
.SUFFIXES: .lo
.c.lo:
-@mkdir objs 2>/dev/null || test -d objs
$(CC) $(SFLAGS) -DPIC -c -o objs/$*.o $<
-@mv objs/$*.o $@
placebo $(SHAREDLIBV): $(PIC_OBJS) libz.a
$(LDSHARED) $(SFLAGS) -o $@ $(PIC_OBJS) $(LDSHAREDLIBC) $(LDFLAGS)
rm -f $(SHAREDLIB) $(SHAREDLIBM)
ln -s $@ $(SHAREDLIB)
ln -s $@ $(SHAREDLIBM)
-@rmdir objs
example$(EXE): example.o $(STATICLIB)
$(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS)
minigzip$(EXE): minigzip.o $(STATICLIB)
$(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS)
examplesh$(EXE): example.o $(SHAREDLIBV)
$(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV)
minigzipsh$(EXE): minigzip.o $(SHAREDLIBV)
$(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV)
example64$(EXE): example64.o $(STATICLIB)
$(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS)
minigzip64$(EXE): minigzip64.o $(STATICLIB)
$(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS)
install-libs: $(LIBS)
-@if [ ! -d $(DESTDIR)$(exec_prefix) ]; then mkdir -p $(DESTDIR)$(exec_prefix); fi
-@if [ ! -d $(DESTDIR)$(libdir) ]; then mkdir -p $(DESTDIR)$(libdir); fi
-@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi
-@if [ ! -d $(DESTDIR)$(man3dir) ]; then mkdir -p $(DESTDIR)$(man3dir); fi
-@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi
cp $(STATICLIB) $(DESTDIR)$(libdir)
chmod 644 $(DESTDIR)$(libdir)/$(STATICLIB)
-@($(RANLIB) $(DESTDIR)$(libdir)/libz.a || true) >/dev/null 2>&1
-@if test -n "$(SHAREDLIBV)"; then \
cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir); \
echo "cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)"; \
chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV); \
echo "chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV)"; \
rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \
ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB); \
ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \
($(LDCONFIG) || true) >/dev/null 2>&1; \
fi
cp zlib.3 $(DESTDIR)$(man3dir)
chmod 644 $(DESTDIR)$(man3dir)/zlib.3
cp zlib.pc $(DESTDIR)$(pkgconfigdir)
chmod 644 $(DESTDIR)$(pkgconfigdir)/zlib.pc
# The ranlib in install is needed on NeXTSTEP which checks file times
# ldconfig is for Linux
install: install-libs
-@if [ ! -d $(DESTDIR)$(includedir) ]; then mkdir -p $(DESTDIR)$(includedir); fi
cp zlib.h zconf.h $(DESTDIR)$(includedir)
chmod 644 $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h
uninstall:
cd $(DESTDIR)$(includedir) && rm -f zlib.h zconf.h
cd $(DESTDIR)$(libdir) && rm -f libz.a; \
if test -n "$(SHAREDLIBV)" -a -f $(SHAREDLIBV); then \
rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
fi
cd $(DESTDIR)$(man3dir) && rm -f zlib.3
cd $(DESTDIR)$(pkgconfigdir) && rm -f zlib.pc
docs: zlib.3.pdf
zlib.3.pdf: zlib.3
groff -mandoc -f H -T ps zlib.3 | ps2pdf - zlib.3.pdf
zconf.h.cmakein: zconf.h.in
-@ TEMPFILE=zconfh_$$; \
echo "/#define ZCONF_H/ a\\\\\n#cmakedefine Z_PREFIX\\\\\n#cmakedefine Z_HAVE_UNISTD_H\n" >> $$TEMPFILE &&\
sed -f $$TEMPFILE zconf.h.in > zconf.h.cmakein &&\
touch -r zconf.h.in zconf.h.cmakein &&\
rm $$TEMPFILE
zconf: zconf.h.in
cp -p zconf.h.in zconf.h
mostlyclean: clean
clean:
rm -f *.o *.lo *~ \
example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \
example64$(EXE) minigzip64$(EXE) \
infcover \
libz.* foo.gz so_locations \
_match.s maketree contrib/infback9/*.o
rm -rf objs
rm -f *.gcda *.gcno *.gcov
rm -f contrib/infback9/*.gcda contrib/infback9/*.gcno contrib/infback9/*.gcov
maintainer-clean: distclean
distclean: clean zconf zconf.h.cmakein docs
rm -f Makefile zlib.pc configure.log
-@rm -f .DS_Store
-@printf 'all:\n\t-@echo "Please use ./configure first. Thank you."\n' > Makefile
-@printf '\ndistclean:\n\tmake -f Makefile.in distclean\n' >> Makefile
-@touch -r Makefile.in Makefile
tags:
etags *.[ch]
depend:
makedepend -- $(CFLAGS) -- *.[ch]
# DO NOT DELETE THIS LINE -- make depend depends on it.
adler32.o zutil.o: zutil.h zlib.h zconf.h
gzclose.o gzlib.o gzread.o gzwrite.o: zlib.h zconf.h gzguts.h
compress.o example.o minigzip.o uncompr.o: zlib.h zconf.h
crc32.o: zutil.h zlib.h zconf.h crc32.h
deflate.o: deflate.h zutil.h zlib.h zconf.h
infback.o inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h
inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inftrees.o: zutil.h zlib.h zconf.h inftrees.h
trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
adler32.lo zutil.lo: zutil.h zlib.h zconf.h
gzclose.lo gzlib.lo gzread.lo gzwrite.lo: zlib.h zconf.h gzguts.h
compress.lo example.lo minigzip.lo uncompr.lo: zlib.h zconf.h
crc32.lo: zutil.h zlib.h zconf.h crc32.h
deflate.lo: deflate.h zutil.h zlib.h zconf.h
infback.lo inflate.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h
inffast.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inftrees.lo: zutil.h zlib.h zconf.h inftrees.h
trees.lo: deflate.h zutil.h zlib.h zconf.h trees.h

115
test/zlib/zlib-1.2.8/README Normal file
View File

@@ -0,0 +1,115 @@
ZLIB DATA COMPRESSION LIBRARY
zlib 1.2.8 is a general purpose data compression library. All the code is
thread safe. The data format used by the zlib library is described by RFCs
(Request for Comments) 1950 to 1952 in the files
http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
rfc1952 (gzip format).
All functions of the compression library are documented in the file zlib.h
(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
of the library is given in the file test/example.c which also tests that
the library is working correctly. Another example is given in the file
test/minigzip.c. The compression library itself is composed of all source
files in the root directory.
To compile all files and run the test program, follow the instructions given at
the top of Makefile.in. In short "./configure; make test", and if that goes
well, "make install" should work for most flavors of Unix. For Windows, use
one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use
make_vms.com.
Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
<info@winimage.com> for the Windows DLL version. The zlib home page is
http://zlib.net/ . Before reporting a problem, please check this site to
verify that you have the latest version of zlib; otherwise get the latest
version and check whether the problem still exists or not.
PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.
Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
issue of Dr. Dobb's Journal; a copy of the article is available at
http://marknelson.us/1997/01/01/zlib-engine/ .
The changes made in version 1.2.8 are documented in the file ChangeLog.
Unsupported third party contributions are provided in directory contrib/ .
zlib is available in Java using the java.util.zip package, documented at
http://java.sun.com/developer/technicalArticles/Programming/compression/ .
A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available
at CPAN (Comprehensive Perl Archive Network) sites, including
http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .
A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
available in Python 1.5 and later versions, see
http://docs.python.org/library/zlib.html .
zlib is built into tcl: http://wiki.tcl.tk/4610 .
An experimental package to read and write files in .zip format, written on top
of zlib by Gilles Vollant <info@winimage.com>, is available in the
contrib/minizip directory of zlib.
Notes for some targets:
- For Windows DLL versions, please see win32/DLL_FAQ.txt
- For 64-bit Irix, deflate.c must be compiled without any optimization. With
-O, one libpng test fails. The test works in 32 bit mode (with the -n32
compiler flag). The compiler bug has been reported to SGI.
- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
when compiled with cc.
- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
necessary to get gzprintf working correctly. This is done by configure.
- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
other compilers. Use "make test" to check your compiler.
- gzdopen is not supported on RISCOS or BEOS.
- For PalmOs, see http://palmzlib.sourceforge.net/
Acknowledgments:
The deflate format used by zlib was defined by Phil Katz. The deflate and
zlib specifications were written by L. Peter Deutsch. Thanks to all the
people who reported problems and suggested various improvements in zlib; they
are too numerous to cite here.
Copyright notice:
(C) 1995-2013 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors 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 software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
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 software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
If you use the zlib library in a product, we would appreciate *not* receiving
lengthy legal documents to sign. The sources are provided for free but without
warranty of any kind. The library has been entirely written by Jean-loup
Gailly and Mark Adler; it does not include third-party code.
If you redistribute modified sources, we would appreciate that you include in
the file ChangeLog history information documenting your changes. Please read
the FAQ for more information on the distribution of modified source versions.

View File

@@ -0,0 +1,179 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "zutil.h"
#define local static
local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
#define BASE 65521 /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
/* use NO_DIVIDE if your processor does not do division in hardware --
try it both ways to see which is faster */
#ifdef NO_DIVIDE
/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
(thank you to John Reiser for pointing this out) */
# define CHOP(a) \
do { \
unsigned long tmp = a >> 16; \
a &= 0xffffUL; \
a += (tmp << 4) - tmp; \
} while (0)
# define MOD28(a) \
do { \
CHOP(a); \
if (a >= BASE) a -= BASE; \
} while (0)
# define MOD(a) \
do { \
CHOP(a); \
MOD28(a); \
} while (0)
# define MOD63(a) \
do { /* this assumes a is not negative */ \
z_off64_t tmp = a >> 32; \
a &= 0xffffffffL; \
a += (tmp << 8) - (tmp << 5) + tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
if (a >= BASE) a -= BASE; \
} while (0)
#else
# define MOD(a) a %= BASE
# define MOD28(a) a %= BASE
# define MOD63(a) a %= BASE
#endif
/* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len)
uLong adler;
const Bytef *buf;
uInt len;
{
unsigned long sum2;
unsigned n;
/* split Adler-32 into component sums */
sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (len == 1) {
adler += buf[0];
if (adler >= BASE)
adler -= BASE;
sum2 += adler;
if (sum2 >= BASE)
sum2 -= BASE;
return adler | (sum2 << 16);
}
/* initial Adler-32 value (deferred check for len == 1 speed) */
if (buf == Z_NULL)
return 1L;
/* in case short lengths are provided, keep it somewhat fast */
if (len < 16) {
while (len--) {
adler += *buf++;
sum2 += adler;
}
if (adler >= BASE)
adler -= BASE;
MOD28(sum2); /* only added so many BASE's */
return adler | (sum2 << 16);
}
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
n = NMAX / 16; /* NMAX is divisible by 16 */
do {
DO16(buf); /* 16 sums unrolled */
buf += 16;
} while (--n);
MOD(adler);
MOD(sum2);
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if (len) { /* avoid modulos if none remaining */
while (len >= 16) {
len -= 16;
DO16(buf);
buf += 16;
}
while (len--) {
adler += *buf++;
sum2 += adler;
}
MOD(adler);
MOD(sum2);
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
local uLong adler32_combine_(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off64_t len2;
{
unsigned long sum1;
unsigned long sum2;
unsigned rem;
/* for negative len, return invalid adler32 as a clue for debugging */
if (len2 < 0)
return 0xffffffffUL;
/* the derivation of this formula is left as an exercise for the reader */
MOD63(len2); /* assumes len2 >= 0 */
rem = (unsigned)len2;
sum1 = adler1 & 0xffff;
sum2 = rem * sum1;
MOD(sum2);
sum1 += (adler2 & 0xffff) + BASE - 1;
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32_combine(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off_t len2;
{
return adler32_combine_(adler1, adler2, len2);
}
uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off64_t len2;
{
return adler32_combine_(adler1, adler2, len2);
}

View File

@@ -0,0 +1,69 @@
# Amiga powerUP (TM) Makefile
# makefile for libpng and SAS C V6.58/7.00 PPC compiler
# Copyright (C) 1998 by Andreas R. Kleinert
LIBNAME = libzip.a
CC = scppc
CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \
OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8 NOVER
AR = ppc-amigaos-ar cr
RANLIB = ppc-amigaos-ranlib
LD = ppc-amigaos-ld -r
LDFLAGS = -o
LDLIBS = LIB:scppc.a LIB:end.o
RM = delete quiet
OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \
uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o
TEST_OBJS = example.o minigzip.o
all: example minigzip
check: test
test: all
example
echo hello world | minigzip | minigzip -d
$(LIBNAME): $(OBJS)
$(AR) $@ $(OBJS)
-$(RANLIB) $@
example: example.o $(LIBNAME)
$(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS)
minigzip: minigzip.o $(LIBNAME)
$(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS)
mostlyclean: clean
clean:
$(RM) *.o example minigzip $(LIBNAME) foo.gz
zip:
zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \
descrip.mms *.[ch]
tgz:
cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \
zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch]
# DO NOT DELETE THIS LINE -- make depend depends on it.
adler32.o: zlib.h zconf.h
compress.o: zlib.h zconf.h
crc32.o: crc32.h zlib.h zconf.h
deflate.o: deflate.h zutil.h zlib.h zconf.h
example.o: zlib.h zconf.h
gzclose.o: zlib.h zconf.h gzguts.h
gzlib.o: zlib.h zconf.h gzguts.h
gzread.o: zlib.h zconf.h gzguts.h
gzwrite.o: zlib.h zconf.h gzguts.h
inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inftrees.o: zutil.h zlib.h zconf.h inftrees.h
minigzip.o: zlib.h zconf.h
trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
uncompr.o: zlib.h zconf.h
zutil.o: zutil.h zlib.h zconf.h

View File

@@ -0,0 +1,68 @@
# SMakefile for zlib
# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly
# Osma Ahvenlampi <Osma.Ahvenlampi@hut.fi>
# Amiga, SAS/C 6.56 & Smake
CC=sc
CFLAGS=OPT
#CFLAGS=OPT CPU=68030
#CFLAGS=DEBUG=LINE
LDFLAGS=LIB z.lib
SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \
NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX \
DEF=POSTINC
OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \
uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o
TEST_OBJS = example.o minigzip.o
all: SCOPTIONS example minigzip
check: test
test: all
example
echo hello world | minigzip | minigzip -d
install: z.lib
copy clone zlib.h zconf.h INCLUDE:
copy clone z.lib LIB:
z.lib: $(OBJS)
oml z.lib r $(OBJS)
example: example.o z.lib
$(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS)
minigzip: minigzip.o z.lib
$(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS)
mostlyclean: clean
clean:
-delete force quiet example minigzip *.o z.lib foo.gz *.lnk SCOPTIONS
SCOPTIONS: Makefile.sas
copy to $@ <from <
$(SCOPTIONS)
<
# DO NOT DELETE THIS LINE -- make depend depends on it.
adler32.o: zlib.h zconf.h
compress.o: zlib.h zconf.h
crc32.o: crc32.h zlib.h zconf.h
deflate.o: deflate.h zutil.h zlib.h zconf.h
example.o: zlib.h zconf.h
gzclose.o: zlib.h zconf.h gzguts.h
gzlib.o: zlib.h zconf.h gzguts.h
gzread.o: zlib.h zconf.h gzguts.h
gzwrite.o: zlib.h zconf.h gzguts.h
inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
inftrees.o: zutil.h zlib.h zconf.h inftrees.h
minigzip.o: zlib.h zconf.h
trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
uncompr.o: zlib.h zconf.h
zutil.o: zutil.h zlib.h zconf.h

View File

@@ -0,0 +1,215 @@
STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('ZLIB')
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/* Version 1.1.3 entry points. */
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/********************************************************************/
/* *MODULE ADLER32 ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("adler32")
/********************************************************************/
/* *MODULE COMPRESS ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("compress")
EXPORT SYMBOL("compress2")
/********************************************************************/
/* *MODULE CRC32 ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("crc32")
EXPORT SYMBOL("get_crc_table")
/********************************************************************/
/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("deflate")
EXPORT SYMBOL("deflateEnd")
EXPORT SYMBOL("deflateSetDictionary")
EXPORT SYMBOL("deflateCopy")
EXPORT SYMBOL("deflateReset")
EXPORT SYMBOL("deflateParams")
EXPORT SYMBOL("deflatePrime")
EXPORT SYMBOL("deflateInit_")
EXPORT SYMBOL("deflateInit2_")
/********************************************************************/
/* *MODULE GZIO ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("gzopen")
EXPORT SYMBOL("gzdopen")
EXPORT SYMBOL("gzsetparams")
EXPORT SYMBOL("gzread")
EXPORT SYMBOL("gzwrite")
EXPORT SYMBOL("gzprintf")
EXPORT SYMBOL("gzputs")
EXPORT SYMBOL("gzgets")
EXPORT SYMBOL("gzputc")
EXPORT SYMBOL("gzgetc")
EXPORT SYMBOL("gzflush")
EXPORT SYMBOL("gzseek")
EXPORT SYMBOL("gzrewind")
EXPORT SYMBOL("gztell")
EXPORT SYMBOL("gzeof")
EXPORT SYMBOL("gzclose")
EXPORT SYMBOL("gzerror")
/********************************************************************/
/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflate")
EXPORT SYMBOL("inflateEnd")
EXPORT SYMBOL("inflateSetDictionary")
EXPORT SYMBOL("inflateSync")
EXPORT SYMBOL("inflateReset")
EXPORT SYMBOL("inflateInit_")
EXPORT SYMBOL("inflateInit2_")
EXPORT SYMBOL("inflateSyncPoint")
/********************************************************************/
/* *MODULE UNCOMPR ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("uncompress")
/********************************************************************/
/* *MODULE ZUTIL ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("zlibVersion")
EXPORT SYMBOL("zError")
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/* Version 1.2.1 additional entry points. */
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/********************************************************************/
/* *MODULE COMPRESS ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("compressBound")
/********************************************************************/
/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("deflateBound")
/********************************************************************/
/* *MODULE GZIO ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("gzungetc")
EXPORT SYMBOL("gzclearerr")
/********************************************************************/
/* *MODULE INFBACK ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflateBack")
EXPORT SYMBOL("inflateBackEnd")
EXPORT SYMBOL("inflateBackInit_")
/********************************************************************/
/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflateCopy")
/********************************************************************/
/* *MODULE ZUTIL ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("zlibCompileFlags")
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/* Version 1.2.5 additional entry points. */
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/********************************************************************/
/* *MODULE ADLER32 ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("adler32_combine")
EXPORT SYMBOL("adler32_combine64")
/********************************************************************/
/* *MODULE CRC32 ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("crc32_combine")
EXPORT SYMBOL("crc32_combine64")
/********************************************************************/
/* *MODULE GZLIB ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("gzbuffer")
EXPORT SYMBOL("gzoffset")
EXPORT SYMBOL("gzoffset64")
EXPORT SYMBOL("gzopen64")
EXPORT SYMBOL("gzseek64")
EXPORT SYMBOL("gztell64")
/********************************************************************/
/* *MODULE GZREAD ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("gzclose_r")
/********************************************************************/
/* *MODULE GZWRITE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("gzclose_w")
/********************************************************************/
/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflateMark")
EXPORT SYMBOL("inflatePrime")
EXPORT SYMBOL("inflateReset2")
EXPORT SYMBOL("inflateUndermine")
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/* Version 1.2.6 additional entry points. */
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/********************************************************************/
/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("deflateResetKeep")
EXPORT SYMBOL("deflatePending")
/********************************************************************/
/* *MODULE GZWRITE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("gzgetc_")
/********************************************************************/
/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflateResetKeep")
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/* Version 1.2.8 additional entry points. */
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/********************************************************************/
/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */
/********************************************************************/
EXPORT SYMBOL("inflateGetDictionary")
ENDPGMEXP

View File

@@ -0,0 +1,110 @@
/******************************************************************************/
/* */
/* ZLIB */
/* */
/* Compile sources into modules and link them into a service program. */
/* */
/******************************************************************************/
PGM
/* Configuration adjustable parameters. */
DCL VAR(&SRCLIB) TYPE(*CHAR) LEN(10) +
VALUE('ZLIB') /* Source library. */
DCL VAR(&SRCFILE) TYPE(*CHAR) LEN(10) +
VALUE('SOURCES') /* Source member file. */
DCL VAR(&CTLFILE) TYPE(*CHAR) LEN(10) +
VALUE('TOOLS') /* Control member file. */
DCL VAR(&MODLIB) TYPE(*CHAR) LEN(10) +
VALUE('ZLIB') /* Module library. */
DCL VAR(&SRVLIB) TYPE(*CHAR) LEN(10) +
VALUE('LGPL') /* Service program library. */
DCL VAR(&CFLAGS) TYPE(*CHAR) +
VALUE('OPTIMIZE(40)') /* Compile options. */
DCL VAR(&TGTRLS) TYPE(*CHAR) +
VALUE('V5R3M0') /* Target release. */
/* Working storage. */
DCL VAR(&CMDLEN) TYPE(*DEC) LEN(15 5) VALUE(300) /* Command length. */
DCL VAR(&CMD) TYPE(*CHAR) LEN(512)
DCL VAR(&FIXDCMD) TYPE(*CHAR) LEN(512)
/* Compile sources into modules. */
CHGVAR VAR(&FIXDCMD) VALUE('CRTCMOD' *BCAT &CFLAGS *BCAT +
'SYSIFCOPT(*IFS64IO)' *BCAT +
'DEFINE(''_LARGEFILE64_SOURCE''' *BCAT +
'''_LFS64_LARGEFILE=1'') TGTRLS(' *TCAT &TGTRLS *TCAT +
') SRCFILE(' *TCAT &SRCLIB *TCAT '/' *TCAT +
&SRCFILE *TCAT ') MODULE(' *TCAT &MODLIB *TCAT '/')
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'ADLER32)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'COMPRESS)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'CRC32)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'DEFLATE)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'GZCLOSE)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'GZLIB)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'GZREAD)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'GZWRITE)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'INFBACK)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'INFFAST)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'INFLATE)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'INFTREES)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'TREES)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'UNCOMPR)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
CHGVAR VAR(&CMD) VALUE(&FIXDCMD *TCAT 'ZUTIL)')
CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN)
/* Link modules into a service program. */
CRTSRVPGM SRVPGM(&SRVLIB/ZLIB) +
MODULE(&MODLIB/ADLER32 &MODLIB/COMPRESS +
&MODLIB/CRC32 &MODLIB/DEFLATE +
&MODLIB/GZCLOSE &MODLIB/GZLIB +
&MODLIB/GZREAD &MODLIB/GZWRITE +
&MODLIB/INFBACK &MODLIB/INFFAST +
&MODLIB/INFLATE &MODLIB/INFTREES +
&MODLIB/TREES &MODLIB/UNCOMPR +
&MODLIB/ZUTIL) +
SRCFILE(&SRCLIB/&CTLFILE) SRCMBR(BNDSRC) +
TEXT('ZLIB 1.2.8') TGTRLS(&TGTRLS)
ENDPGM

View File

@@ -0,0 +1,115 @@
ZLIB version 1.2.8 for AS400 installation instructions
I) From an AS400 *SAVF file:
1) Unpacking archive to an AS400 save file
On the AS400:
_ Create the ZLIB AS400 library:
CRTLIB LIB(ZLIB) TYPE(*PROD) TEXT('ZLIB compression API library')
_ Create a work save file, for example:
CRTSAVF FILE(ZLIB/ZLIBSAVF)
On a PC connected to the target AS400:
_ Unpack the save file image to a PC file "ZLIBSAVF"
_ Upload this file into the save file on the AS400, for example
using ftp in BINARY mode.
2) Populating the ZLIB AS400 source library
On the AS400:
_ Extract the saved objects into the ZLIB AS400 library using:
RSTOBJ OBJ(*ALL) SAVLIB(ZLIB) DEV(*SAVF) SAVF(ZLIB/ZLIBSAVF) RSTLIB(ZLIB)
3) Customize installation:
_ Edit CL member ZLIB/TOOLS(COMPILE) and change parameters if needed,
according to the comments.
_ Compile this member with:
CRTCLPGM PGM(ZLIB/COMPILE) SRCFILE(ZLIB/TOOLS) SRCMBR(COMPILE)
4) Compile and generate the service program:
_ This can now be done by executing:
CALL PGM(ZLIB/COMPILE)
II) From the original source distribution:
1) On the AS400, create the source library:
CRTLIB LIB(ZLIB) TYPE(*PROD) TEXT('ZLIB compression API library')
2) Create the source files:
CRTSRCPF FILE(ZLIB/SOURCES) RCDLEN(112) TEXT('ZLIB library modules')
CRTSRCPF FILE(ZLIB/H) RCDLEN(112) TEXT('ZLIB library includes')
CRTSRCPF FILE(ZLIB/TOOLS) RCDLEN(112) TEXT('ZLIB library control utilities')
3) From the machine hosting the distribution files, upload them (with
FTP in text mode, for example) according to the following table:
Original AS400 AS400 AS400 AS400
file file member type description
SOURCES Original ZLIB C subprogram sources
adler32.c ADLER32 C ZLIB - Compute the Adler-32 checksum of a dta strm
compress.c COMPRESS C ZLIB - Compress a memory buffer
crc32.c CRC32 C ZLIB - Compute the CRC-32 of a data stream
deflate.c DEFLATE C ZLIB - Compress data using the deflation algorithm
gzclose.c GZCLOSE C ZLIB - Close .gz files
gzlib.c GZLIB C ZLIB - Miscellaneous .gz files IO support
gzread.c GZREAD C ZLIB - Read .gz files
gzwrite.c GZWRITE C ZLIB - Write .gz files
infback.c INFBACK C ZLIB - Inflate using a callback interface
inffast.c INFFAST C ZLIB - Fast proc. literals & length/distance pairs
inflate.c INFLATE C ZLIB - Interface to inflate modules
inftrees.c INFTREES C ZLIB - Generate Huffman trees for efficient decode
trees.c TREES C ZLIB - Output deflated data using Huffman coding
uncompr.c UNCOMPR C ZLIB - Decompress a memory buffer
zutil.c ZUTIL C ZLIB - Target dependent utility functions
H Original ZLIB C and ILE/RPG include files
crc32.h CRC32 C ZLIB - CRC32 tables
deflate.h DEFLATE C ZLIB - Internal compression state
gzguts.h GZGUTS C ZLIB - Definitions for the gzclose module
inffast.h INFFAST C ZLIB - Header to use inffast.c
inffixed.h INFFIXED C ZLIB - Table for decoding fixed codes
inflate.h INFLATE C ZLIB - Internal inflate state definitions
inftrees.h INFTREES C ZLIB - Header to use inftrees.c
trees.h TREES C ZLIB - Created automatically with -DGEN_TREES_H
zconf.h ZCONF C ZLIB - Compression library configuration
zlib.h ZLIB C ZLIB - Compression library C user interface
as400/zlib.inc ZLIB.INC RPGLE ZLIB - Compression library ILE RPG user interface
zutil.h ZUTIL C ZLIB - Internal interface and configuration
TOOLS Building source software & AS/400 README
as400/bndsrc BNDSRC Entry point exportation list
as400/compile.clp COMPILE CLP Compile sources & generate service program
as400/readme.txt README TXT Installation instructions
4) Continue as in I)3).
Notes: For AS400 ILE RPG programmers, a /copy member defining the ZLIB
API prototypes for ILE RPG can be found in ZLIB/H(ZLIB.INC).
Please read comments in this member for more information.
Remember that most foreign textual data are ASCII coded: this
implementation does not handle conversion from/to ASCII, so
text data code conversions must be done explicitely.
Mainly for the reason above, always open zipped files in binary mode.

View File

@@ -0,0 +1,451 @@
* ZLIB.INC - Interface to the general purpose compression library
*
* ILE RPG400 version by Patrick Monnerat, DATASPHERE.
* Version 1.2.8
*
*
* WARNING:
* Procedures inflateInit(), inflateInit2(), deflateInit(),
* deflateInit2() and inflateBackInit() need to be called with
* two additional arguments:
* the package version string and the stream control structure.
* size. This is needed because RPG lacks some macro feature.
* Call these procedures as:
* inflateInit(...: ZLIB_VERSION: %size(z_stream))
*
/if not defined(ZLIB_H_)
/define ZLIB_H_
*
**************************************************************************
* Constants
**************************************************************************
*
* Versioning information.
*
D ZLIB_VERSION C '1.2.8'
D ZLIB_VERNUM C X'1280'
D ZLIB_VER_MAJOR C 1
D ZLIB_VER_MINOR C 2
D ZLIB_VER_REVISION...
D C 8
D ZLIB_VER_SUBREVISION...
D C 0
*
* Other equates.
*
D Z_NO_FLUSH C 0
D Z_PARTIAL_FLUSH...
D C 1
D Z_SYNC_FLUSH C 2
D Z_FULL_FLUSH C 3
D Z_FINISH C 4
D Z_BLOCK C 5
D Z_TREES C 6
*
D Z_OK C 0
D Z_STREAM_END C 1
D Z_NEED_DICT C 2
D Z_ERRNO C -1
D Z_STREAM_ERROR C -2
D Z_DATA_ERROR C -3
D Z_MEM_ERROR C -4
D Z_BUF_ERROR C -5
DZ_VERSION_ERROR C -6
*
D Z_NO_COMPRESSION...
D C 0
D Z_BEST_SPEED C 1
D Z_BEST_COMPRESSION...
D C 9
D Z_DEFAULT_COMPRESSION...
D C -1
*
D Z_FILTERED C 1
D Z_HUFFMAN_ONLY C 2
D Z_RLE C 3
D Z_DEFAULT_STRATEGY...
D C 0
*
D Z_BINARY C 0
D Z_ASCII C 1
D Z_UNKNOWN C 2
*
D Z_DEFLATED C 8
*
D Z_NULL C 0
*
**************************************************************************
* Types
**************************************************************************
*
D z_streamp S * Stream struct ptr
D gzFile S * File pointer
D z_off_t S 10i 0 Stream offsets
D z_off64_t S 20i 0 Stream offsets
*
**************************************************************************
* Structures
**************************************************************************
*
* The GZIP encode/decode stream support structure.
*
D z_stream DS align based(z_streamp)
D zs_next_in * Next input byte
D zs_avail_in 10U 0 Byte cnt at next_in
D zs_total_in 10U 0 Total bytes read
D zs_next_out * Output buffer ptr
D zs_avail_out 10U 0 Room left @ next_out
D zs_total_out 10U 0 Total bytes written
D zs_msg * Last errmsg or null
D zs_state * Internal state
D zs_zalloc * procptr Int. state allocator
D zs_free * procptr Int. state dealloc.
D zs_opaque * Private alloc. data
D zs_data_type 10i 0 ASC/BIN best guess
D zs_adler 10u 0 Uncompr. adler32 val
D 10U 0 Reserved
D 10U 0 Ptr. alignment
*
**************************************************************************
* Utility function prototypes
**************************************************************************
*
D compress PR 10I 0 extproc('compress')
D dest 65535 options(*varsize) Destination buffer
D destLen 10U 0 Destination length
D source 65535 const options(*varsize) Source buffer
D sourceLen 10u 0 value Source length
*
D compress2 PR 10I 0 extproc('compress2')
D dest 65535 options(*varsize) Destination buffer
D destLen 10U 0 Destination length
D source 65535 const options(*varsize) Source buffer
D sourceLen 10U 0 value Source length
D level 10I 0 value Compression level
*
D compressBound PR 10U 0 extproc('compressBound')
D sourceLen 10U 0 value
*
D uncompress PR 10I 0 extproc('uncompress')
D dest 65535 options(*varsize) Destination buffer
D destLen 10U 0 Destination length
D source 65535 const options(*varsize) Source buffer
D sourceLen 10U 0 value Source length
*
/if not defined(LARGE_FILES)
D gzopen PR extproc('gzopen')
D like(gzFile)
D path * value options(*string) File pathname
D mode * value options(*string) Open mode
/else
D gzopen PR extproc('gzopen64')
D like(gzFile)
D path * value options(*string) File pathname
D mode * value options(*string) Open mode
*
D gzopen64 PR extproc('gzopen64')
D like(gzFile)
D path * value options(*string) File pathname
D mode * value options(*string) Open mode
/endif
*
D gzdopen PR extproc('gzdopen')
D like(gzFile)
D fd 10I 0 value File descriptor
D mode * value options(*string) Open mode
*
D gzbuffer PR 10I 0 extproc('gzbuffer')
D file value like(gzFile) File pointer
D size 10U 0 value
*
D gzsetparams PR 10I 0 extproc('gzsetparams')
D file value like(gzFile) File pointer
D level 10I 0 value
D strategy 10I 0 value
*
D gzread PR 10I 0 extproc('gzread')
D file value like(gzFile) File pointer
D buf 65535 options(*varsize) Buffer
D len 10u 0 value Buffer length
*
D gzwrite PR 10I 0 extproc('gzwrite')
D file value like(gzFile) File pointer
D buf 65535 const options(*varsize) Buffer
D len 10u 0 value Buffer length
*
D gzputs PR 10I 0 extproc('gzputs')
D file value like(gzFile) File pointer
D s * value options(*string) String to output
*
D gzgets PR * extproc('gzgets')
D file value like(gzFile) File pointer
D buf 65535 options(*varsize) Read buffer
D len 10i 0 value Buffer length
*
D gzputc PR 10i 0 extproc('gzputc')
D file value like(gzFile) File pointer
D c 10I 0 value Character to write
*
D gzgetc PR 10i 0 extproc('gzgetc')
D file value like(gzFile) File pointer
*
D gzgetc_ PR 10i 0 extproc('gzgetc_')
D file value like(gzFile) File pointer
*
D gzungetc PR 10i 0 extproc('gzungetc')
D c 10I 0 value Character to push
D file value like(gzFile) File pointer
*
D gzflush PR 10i 0 extproc('gzflush')
D file value like(gzFile) File pointer
D flush 10I 0 value Type of flush
*
/if not defined(LARGE_FILES)
D gzseek PR extproc('gzseek')
D like(z_off_t)
D file value like(gzFile) File pointer
D offset value like(z_off_t) Offset
D whence 10i 0 value Origin
/else
D gzseek PR extproc('gzseek64')
D like(z_off_t)
D file value like(gzFile) File pointer
D offset value like(z_off_t) Offset
D whence 10i 0 value Origin
*
D gzseek64 PR extproc('gzseek64')
D like(z_off64_t)
D file value like(gzFile) File pointer
D offset value like(z_off64_t) Offset
D whence 10i 0 value Origin
/endif
*
D gzrewind PR 10i 0 extproc('gzrewind')
D file value like(gzFile) File pointer
*
/if not defined(LARGE_FILES)
D gztell PR extproc('gztell')
D like(z_off_t)
D file value like(gzFile) File pointer
/else
D gztell PR extproc('gztell64')
D like(z_off_t)
D file value like(gzFile) File pointer
*
D gztell64 PR extproc('gztell64')
D like(z_off64_t)
D file value like(gzFile) File pointer
/endif
*
/if not defined(LARGE_FILES)
D gzoffset PR extproc('gzoffset')
D like(z_off_t)
D file value like(gzFile) File pointer
/else
D gzoffset PR extproc('gzoffset64')
D like(z_off_t)
D file value like(gzFile) File pointer
*
D gzoffset64 PR extproc('gzoffset64')
D like(z_off64_t)
D file value like(gzFile) File pointer
/endif
*
D gzeof PR 10i 0 extproc('gzeof')
D file value like(gzFile) File pointer
*
D gzclose_r PR 10i 0 extproc('gzclose_r')
D file value like(gzFile) File pointer
*
D gzclose_w PR 10i 0 extproc('gzclose_w')
D file value like(gzFile) File pointer
*
D gzclose PR 10i 0 extproc('gzclose')
D file value like(gzFile) File pointer
*
D gzerror PR * extproc('gzerror') Error string
D file value like(gzFile) File pointer
D errnum 10I 0 Error code
*
D gzclearerr PR extproc('gzclearerr')
D file value like(gzFile) File pointer
*
**************************************************************************
* Basic function prototypes
**************************************************************************
*
D zlibVersion PR * extproc('zlibVersion') Version string
*
D deflateInit PR 10I 0 extproc('deflateInit_') Init. compression
D strm like(z_stream) Compression stream
D level 10I 0 value Compression level
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D deflate PR 10I 0 extproc('deflate') Compress data
D strm like(z_stream) Compression stream
D flush 10I 0 value Flush type required
*
D deflateEnd PR 10I 0 extproc('deflateEnd') Termin. compression
D strm like(z_stream) Compression stream
*
D inflateInit PR 10I 0 extproc('inflateInit_') Init. expansion
D strm like(z_stream) Expansion stream
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D inflate PR 10I 0 extproc('inflate') Expand data
D strm like(z_stream) Expansion stream
D flush 10I 0 value Flush type required
*
D inflateEnd PR 10I 0 extproc('inflateEnd') Termin. expansion
D strm like(z_stream) Expansion stream
*
**************************************************************************
* Advanced function prototypes
**************************************************************************
*
D deflateInit2 PR 10I 0 extproc('deflateInit2_') Init. compression
D strm like(z_stream) Compression stream
D level 10I 0 value Compression level
D method 10I 0 value Compression method
D windowBits 10I 0 value log2(window size)
D memLevel 10I 0 value Mem/cmpress tradeoff
D strategy 10I 0 value Compression stategy
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D deflateSetDictionary...
D PR 10I 0 extproc('deflateSetDictionary') Init. dictionary
D strm like(z_stream) Compression stream
D dictionary 65535 const options(*varsize) Dictionary bytes
D dictLength 10U 0 value Dictionary length
*
D deflateCopy PR 10I 0 extproc('deflateCopy') Compress strm 2 strm
D dest like(z_stream) Destination stream
D source like(z_stream) Source stream
*
D deflateReset PR 10I 0 extproc('deflateReset') End and init. stream
D strm like(z_stream) Compression stream
*
D deflateParams PR 10I 0 extproc('deflateParams') Change level & strat
D strm like(z_stream) Compression stream
D level 10I 0 value Compression level
D strategy 10I 0 value Compression stategy
*
D deflateBound PR 10U 0 extproc('deflateBound') Change level & strat
D strm like(z_stream) Compression stream
D sourcelen 10U 0 value Compression level
*
D deflatePending PR 10I 0 extproc('deflatePending') Change level & strat
D strm like(z_stream) Compression stream
D pending 10U 0 Pending bytes
D bits 10I 0 Pending bits
*
D deflatePrime PR 10I 0 extproc('deflatePrime') Change level & strat
D strm like(z_stream) Compression stream
D bits 10I 0 value # of bits to insert
D value 10I 0 value Bits to insert
*
D inflateInit2 PR 10I 0 extproc('inflateInit2_') Init. expansion
D strm like(z_stream) Expansion stream
D windowBits 10I 0 value log2(window size)
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D inflateSetDictionary...
D PR 10I 0 extproc('inflateSetDictionary') Init. dictionary
D strm like(z_stream) Expansion stream
D dictionary 65535 const options(*varsize) Dictionary bytes
D dictLength 10U 0 value Dictionary length
*
D inflateGetDictionary...
D PR 10I 0 extproc('inflateGetDictionary') Get dictionary
D strm like(z_stream) Expansion stream
D dictionary 65535 options(*varsize) Dictionary bytes
D dictLength 10U 0 Dictionary length
*
D inflateSync PR 10I 0 extproc('inflateSync') Sync. expansion
D strm like(z_stream) Expansion stream
*
D inflateCopy PR 10I 0 extproc('inflateCopy')
D dest like(z_stream) Destination stream
D source like(z_stream) Source stream
*
D inflateReset PR 10I 0 extproc('inflateReset') End and init. stream
D strm like(z_stream) Expansion stream
*
D inflateReset2 PR 10I 0 extproc('inflateReset2') End and init. stream
D strm like(z_stream) Expansion stream
D windowBits 10I 0 value Log2(buffer size)
*
D inflatePrime PR 10I 0 extproc('inflatePrime') Insert bits
D strm like(z_stream) Expansion stream
D bits 10I 0 value Bit count
D value 10I 0 value Bits to insert
*
D inflateMark PR 10I 0 extproc('inflateMark') Get inflate info
D strm like(z_stream) Expansion stream
*
D inflateBackInit...
D PR 10I 0 extproc('inflateBackInit_')
D strm like(z_stream) Expansion stream
D windowBits 10I 0 value Log2(buffer size)
D window 65535 options(*varsize) Buffer
D version * value options(*string) Version string
D stream_size 10i 0 value Stream struct. size
*
D inflateBack PR 10I 0 extproc('inflateBack')
D strm like(z_stream) Expansion stream
D in * value procptr Input function
D in_desc * value Input descriptor
D out * value procptr Output function
D out_desc * value Output descriptor
*
D inflateBackEnd PR 10I 0 extproc('inflateBackEnd')
D strm like(z_stream) Expansion stream
*
D zlibCompileFlags...
D PR 10U 0 extproc('zlibCompileFlags')
*
**************************************************************************
* Checksum function prototypes
**************************************************************************
*
D adler32 PR 10U 0 extproc('adler32') New checksum
D adler 10U 0 value Old checksum
D buf 65535 const options(*varsize) Bytes to accumulate
D len 10U 0 value Buffer length
*
D crc32 PR 10U 0 extproc('crc32') New checksum
D crc 10U 0 value Old checksum
D buf 65535 const options(*varsize) Bytes to accumulate
D len 10U 0 value Buffer length
*
**************************************************************************
* Miscellaneous function prototypes
**************************************************************************
*
D zError PR * extproc('zError') Error string
D err 10I 0 value Error code
*
D inflateSyncPoint...
D PR 10I 0 extproc('inflateSyncPoint')
D strm like(z_stream) Expansion stream
*
D get_crc_table PR * extproc('get_crc_table') Ptr to ulongs
*
D inflateUndermine...
D PR 10I 0 extproc('inflateUndermine')
D strm like(z_stream) Expansion stream
D arg 10I 0 value Error code
*
D inflateResetKeep...
D PR 10I 0 extproc('inflateResetKeep') End and init. stream
D strm like(z_stream) Expansion stream
*
D deflateResetKeep...
D PR 10I 0 extproc('deflateResetKeep') End and init. stream
D strm like(z_stream) Expansion stream
*
/endif

View File

@@ -0,0 +1,80 @@
/* compress.c -- compress a memory buffer
* Copyright (C) 1995-2005 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#define ZLIB_INTERNAL
#include "zlib.h"
/* ===========================================================================
Compresses the source buffer into the destination buffer. The level
parameter has the same meaning as in deflateInit. sourceLen is the byte
length of the source buffer. Upon entry, destLen is the total size of the
destination buffer, which must be at least 0.1% larger than sourceLen plus
12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid.
*/
int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
int level;
{
z_stream stream;
int err;
stream.next_in = (z_const Bytef *)source;
stream.avail_in = (uInt)sourceLen;
#ifdef MAXSEG_64K
/* Check for source > 64K on 16-bit machine: */
if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
#endif
stream.next_out = dest;
stream.avail_out = (uInt)*destLen;
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = deflateInit(&stream, level);
if (err != Z_OK) return err;
err = deflate(&stream, Z_FINISH);
if (err != Z_STREAM_END) {
deflateEnd(&stream);
return err == Z_OK ? Z_BUF_ERROR : err;
}
*destLen = stream.total_out;
err = deflateEnd(&stream);
return err;
}
/* ===========================================================================
*/
int ZEXPORT compress (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
{
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
}
/* ===========================================================================
If the default memLevel or windowBits for deflateInit() is changed, then
this function needs to be updated.
*/
uLong ZEXPORT compressBound (sourceLen)
uLong sourceLen;
{
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
(sourceLen >> 25) + 13;
}

831
test/zlib/zlib-1.2.8/configure vendored Normal file
View File

@@ -0,0 +1,831 @@
#!/bin/sh
# configure script for zlib.
#
# Normally configure builds both a static and a shared library.
# If you want to build just a static library, use: ./configure --static
#
# To impose specific compiler or flags or install directory, use for example:
# prefix=$HOME CC=cc CFLAGS="-O4" ./configure
# or for csh/tcsh users:
# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
# If you have problems, try without defining CC and CFLAGS before reporting
# an error.
# start off configure.log
echo -------------------- >> configure.log
echo $0 $* >> configure.log
date >> configure.log
# set command prefix for cross-compilation
if [ -n "${CHOST}" ]; then
uname="`echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/'`"
CROSS_PREFIX="${CHOST}-"
fi
# destination name for static library
STATICLIB=libz.a
# extract zlib version numbers from zlib.h
VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
VER3=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\\.[0-9]*\).*/\1/p' < zlib.h`
VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h`
VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h`
# establish commands for library building
if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then
AR=${AR-"${CROSS_PREFIX}ar"}
test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log
else
AR=${AR-"ar"}
test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log
fi
ARFLAGS=${ARFLAGS-"rc"}
if "${CROSS_PREFIX}ranlib" --version >/dev/null 2>/dev/null || test $? -lt 126; then
RANLIB=${RANLIB-"${CROSS_PREFIX}ranlib"}
test -n "${CROSS_PREFIX}" && echo Using ${RANLIB} | tee -a configure.log
else
RANLIB=${RANLIB-"ranlib"}
fi
if "${CROSS_PREFIX}nm" --version >/dev/null 2>/dev/null || test $? -lt 126; then
NM=${NM-"${CROSS_PREFIX}nm"}
test -n "${CROSS_PREFIX}" && echo Using ${NM} | tee -a configure.log
else
NM=${NM-"nm"}
fi
# set defaults before processing command line options
LDCONFIG=${LDCONFIG-"ldconfig"}
LDSHAREDLIBC="${LDSHAREDLIBC--lc}"
ARCHS=
prefix=${prefix-/usr/local}
exec_prefix=${exec_prefix-'${prefix}'}
libdir=${libdir-'${exec_prefix}/lib'}
sharedlibdir=${sharedlibdir-'${libdir}'}
includedir=${includedir-'${prefix}/include'}
mandir=${mandir-'${prefix}/share/man'}
shared_ext='.so'
shared=1
solo=0
cover=0
zprefix=0
zconst=0
build64=0
gcc=0
old_cc="$CC"
old_cflags="$CFLAGS"
OBJC='$(OBJZ) $(OBJG)'
PIC_OBJC='$(PIC_OBJZ) $(PIC_OBJG)'
# leave this script, optionally in a bad way
leave()
{
if test "$*" != "0"; then
echo "** $0 aborting." | tee -a configure.log
fi
rm -f $test.[co] $test $test$shared_ext $test.gcno ./--version
echo -------------------- >> configure.log
echo >> configure.log
echo >> configure.log
exit $1
}
# process command line options
while test $# -ge 1
do
case "$1" in
-h* | --help)
echo 'usage:' | tee -a configure.log
echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log
echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log
echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log
exit 0 ;;
-p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;;
-e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;;
-l*=* | --libdir=*) libdir=`echo $1 | sed 's/.*=//'`; shift ;;
--sharedlibdir=*) sharedlibdir=`echo $1 | sed 's/.*=//'`; shift ;;
-i*=* | --includedir=*) includedir=`echo $1 | sed 's/.*=//'`;shift ;;
-u*=* | --uname=*) uname=`echo $1 | sed 's/.*=//'`;shift ;;
-p* | --prefix) prefix="$2"; shift; shift ;;
-e* | --eprefix) exec_prefix="$2"; shift; shift ;;
-l* | --libdir) libdir="$2"; shift; shift ;;
-i* | --includedir) includedir="$2"; shift; shift ;;
-s* | --shared | --enable-shared) shared=1; shift ;;
-t | --static) shared=0; shift ;;
--solo) solo=1; shift ;;
--cover) cover=1; shift ;;
-z* | --zprefix) zprefix=1; shift ;;
-6* | --64) build64=1; shift ;;
-a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;;
--sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;;
--localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;;
-c* | --const) zconst=1; shift ;;
*)
echo "unknown option: $1" | tee -a configure.log
echo "$0 --help for help" | tee -a configure.log
leave 1;;
esac
done
# temporary file name
test=ztest$$
# put arguments in log, also put test file in log if used in arguments
show()
{
case "$*" in
*$test.c*)
echo === $test.c === >> configure.log
cat $test.c >> configure.log
echo === >> configure.log;;
esac
echo $* >> configure.log
}
# check for gcc vs. cc and set compile and link flags based on the system identified by uname
cat > $test.c <<EOF
extern int getchar();
int hello() {return getchar();}
EOF
test -z "$CC" && echo Checking for ${CROSS_PREFIX}gcc... | tee -a configure.log
cc=${CC-${CROSS_PREFIX}gcc}
cflags=${CFLAGS-"-O3"}
# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure
case "$cc" in
*gcc*) gcc=1 ;;
*clang*) gcc=1 ;;
esac
case `$cc -v 2>&1` in
*gcc*) gcc=1 ;;
esac
show $cc -c $test.c
if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then
echo ... using gcc >> configure.log
CC="$cc"
CFLAGS="${CFLAGS--O3} ${ARCHS}"
SFLAGS="${CFLAGS--O3} -fPIC"
LDFLAGS="${LDFLAGS} ${ARCHS}"
if test $build64 -eq 1; then
CFLAGS="${CFLAGS} -m64"
SFLAGS="${SFLAGS} -m64"
fi
if test "${ZLIBGCCWARN}" = "YES"; then
if test "$zconst" -eq 1; then
CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -pedantic -DZLIB_CONST"
else
CFLAGS="${CFLAGS} -Wall -Wextra -pedantic"
fi
fi
if test -z "$uname"; then
uname=`(uname -s || echo unknown) 2>/dev/null`
fi
case "$uname" in
Linux* | linux* | GNU | GNU/* | solaris*)
LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"} ;;
*BSD | *bsd* | DragonFly)
LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"}
LDCONFIG="ldconfig -m" ;;
CYGWIN* | Cygwin* | cygwin* | OS/2*)
EXE='.exe' ;;
MINGW* | mingw*)
# temporary bypass
rm -f $test.[co] $test $test$shared_ext
echo "Please use win32/Makefile.gcc instead." | tee -a configure.log
leave 1
LDSHARED=${LDSHARED-"$cc -shared"}
LDSHAREDLIBC=""
EXE='.exe' ;;
QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4
# (alain.bonnefoy@icbt.com)
LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;;
HP-UX*)
LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"}
case `(uname -m || echo unknown) 2>/dev/null` in
ia64)
shared_ext='.so'
SHAREDLIB='libz.so' ;;
*)
shared_ext='.sl'
SHAREDLIB='libz.sl' ;;
esac ;;
Darwin* | darwin*)
shared_ext='.dylib'
SHAREDLIB=libz$shared_ext
SHAREDLIBV=libz.$VER$shared_ext
SHAREDLIBM=libz.$VER1$shared_ext
LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"}
if libtool -V 2>&1 | grep Apple > /dev/null; then
AR="libtool"
else
AR="/usr/bin/libtool"
fi
ARFLAGS="-o" ;;
*) LDSHARED=${LDSHARED-"$cc -shared"} ;;
esac
else
# find system name and corresponding cc options
CC=${CC-cc}
gcc=0
echo ... using $CC >> configure.log
if test -z "$uname"; then
uname=`(uname -sr || echo unknown) 2>/dev/null`
fi
case "$uname" in
HP-UX*) SFLAGS=${CFLAGS-"-O +z"}
CFLAGS=${CFLAGS-"-O"}
# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
LDSHARED=${LDSHARED-"ld -b"}
case `(uname -m || echo unknown) 2>/dev/null` in
ia64)
shared_ext='.so'
SHAREDLIB='libz.so' ;;
*)
shared_ext='.sl'
SHAREDLIB='libz.sl' ;;
esac ;;
IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
CFLAGS=${CFLAGS-"-ansi -O2"}
LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;;
OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
CFLAGS=${CFLAGS-"-O -std1"}
LDFLAGS="${LDFLAGS} -Wl,-rpath,."
LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"} ;;
OSF1*) SFLAGS=${CFLAGS-"-O -std1"}
CFLAGS=${CFLAGS-"-O -std1"}
LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;;
QNX*) SFLAGS=${CFLAGS-"-4 -O"}
CFLAGS=${CFLAGS-"-4 -O"}
LDSHARED=${LDSHARED-"cc"}
RANLIB=${RANLIB-"true"}
AR="cc"
ARFLAGS="-A" ;;
SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
CFLAGS=${CFLAGS-"-O3"}
LDSHARED=${LDSHARED-"cc -dy -KPIC -G"} ;;
SunOS\ 5* | solaris*)
LDSHARED=${LDSHARED-"cc -G -h libz$shared_ext.$VER1"}
SFLAGS=${CFLAGS-"-fast -KPIC"}
CFLAGS=${CFLAGS-"-fast"}
if test $build64 -eq 1; then
# old versions of SunPRO/Workshop/Studio don't support -m64,
# but newer ones do. Check for it.
flag64=`$CC -flags | egrep -- '^-m64'`
if test x"$flag64" != x"" ; then
CFLAGS="${CFLAGS} -m64"
SFLAGS="${SFLAGS} -m64"
else
case `(uname -m || echo unknown) 2>/dev/null` in
i86*)
SFLAGS="$SFLAGS -xarch=amd64"
CFLAGS="$CFLAGS -xarch=amd64" ;;
*)
SFLAGS="$SFLAGS -xarch=v9"
CFLAGS="$CFLAGS -xarch=v9" ;;
esac
fi
fi
;;
SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
CFLAGS=${CFLAGS-"-O2"}
LDSHARED=${LDSHARED-"ld"} ;;
SunStudio\ 9*) SFLAGS=${CFLAGS-"-fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"}
CFLAGS=${CFLAGS-"-fast -xtarget=ultra3 -xarch=v9b"}
LDSHARED=${LDSHARED-"cc -xarch=v9b"} ;;
UNIX_System_V\ 4.2.0)
SFLAGS=${CFLAGS-"-KPIC -O"}
CFLAGS=${CFLAGS-"-O"}
LDSHARED=${LDSHARED-"cc -G"} ;;
UNIX_SV\ 4.2MP)
SFLAGS=${CFLAGS-"-Kconform_pic -O"}
CFLAGS=${CFLAGS-"-O"}
LDSHARED=${LDSHARED-"cc -G"} ;;
OpenUNIX\ 5)
SFLAGS=${CFLAGS-"-KPIC -O"}
CFLAGS=${CFLAGS-"-O"}
LDSHARED=${LDSHARED-"cc -G"} ;;
AIX*) # Courtesy of dbakker@arrayasolutions.com
SFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
CFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
LDSHARED=${LDSHARED-"xlc -G"} ;;
# send working options for other systems to zlib@gzip.org
*) SFLAGS=${CFLAGS-"-O"}
CFLAGS=${CFLAGS-"-O"}
LDSHARED=${LDSHARED-"cc -shared"} ;;
esac
fi
# destination names for shared library if not defined above
SHAREDLIB=${SHAREDLIB-"libz$shared_ext"}
SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"}
SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"}
echo >> configure.log
# define functions for testing compiler and library characteristics and logging the results
cat > $test.c <<EOF
#error error
EOF
if ($CC -c $CFLAGS $test.c) 2>/dev/null; then
try()
{
show $*
test "`( $* ) 2>&1 | tee -a configure.log`" = ""
}
echo - using any output from compiler to indicate an error >> configure.log
else
try()
{
show $*
( $* ) >> configure.log 2>&1
ret=$?
if test $ret -ne 0; then
echo "(exit code "$ret")" >> configure.log
fi
return $ret
}
fi
tryboth()
{
show $*
got=`( $* ) 2>&1`
ret=$?
printf %s "$got" >> configure.log
if test $ret -ne 0; then
return $ret
fi
test "$got" = ""
}
cat > $test.c << EOF
int foo() { return 0; }
EOF
echo "Checking for obsessive-compulsive compiler options..." >> configure.log
if try $CC -c $CFLAGS $test.c; then
:
else
echo "Compiler error reporting is too harsh for $0 (perhaps remove -Werror)." | tee -a configure.log
leave 1
fi
echo >> configure.log
# see if shared library build supported
cat > $test.c <<EOF
extern int getchar();
int hello() {return getchar();}
EOF
if test $shared -eq 1; then
echo Checking for shared library support... | tee -a configure.log
# we must test in two steps (cc then ld), required at least on SunOS 4.x
if try $CC -w -c $SFLAGS $test.c &&
try $LDSHARED $SFLAGS -o $test$shared_ext $test.o; then
echo Building shared library $SHAREDLIBV with $CC. | tee -a configure.log
elif test -z "$old_cc" -a -z "$old_cflags"; then
echo No shared library support. | tee -a configure.log
shared=0;
else
echo 'No shared library support; try without defining CC and CFLAGS' | tee -a configure.log
shared=0;
fi
fi
if test $shared -eq 0; then
LDSHARED="$CC"
ALL="static"
TEST="all teststatic"
SHAREDLIB=""
SHAREDLIBV=""
SHAREDLIBM=""
echo Building static library $STATICLIB version $VER with $CC. | tee -a configure.log
else
ALL="static shared"
TEST="all teststatic testshared"
fi
# check for underscores in external names for use by assembler code
CPP=${CPP-"$CC -E"}
case $CFLAGS in
*ASMV*)
echo >> configure.log
show "$NM $test.o | grep _hello"
if test "`$NM $test.o | grep _hello | tee -a configure.log`" = ""; then
CPP="$CPP -DNO_UNDERLINE"
echo Checking for underline in external names... No. | tee -a configure.log
else
echo Checking for underline in external names... Yes. | tee -a configure.log
fi ;;
esac
echo >> configure.log
# check for large file support, and if none, check for fseeko()
cat > $test.c <<EOF
#include <sys/types.h>
off64_t dummy = 0;
EOF
if try $CC -c $CFLAGS -D_LARGEFILE64_SOURCE=1 $test.c; then
CFLAGS="${CFLAGS} -D_LARGEFILE64_SOURCE=1"
SFLAGS="${SFLAGS} -D_LARGEFILE64_SOURCE=1"
ALL="${ALL} all64"
TEST="${TEST} test64"
echo "Checking for off64_t... Yes." | tee -a configure.log
echo "Checking for fseeko... Yes." | tee -a configure.log
else
echo "Checking for off64_t... No." | tee -a configure.log
echo >> configure.log
cat > $test.c <<EOF
#include <stdio.h>
int main(void) {
fseeko(NULL, 0, 0);
return 0;
}
EOF
if try $CC $CFLAGS -o $test $test.c; then
echo "Checking for fseeko... Yes." | tee -a configure.log
else
CFLAGS="${CFLAGS} -DNO_FSEEKO"
SFLAGS="${SFLAGS} -DNO_FSEEKO"
echo "Checking for fseeko... No." | tee -a configure.log
fi
fi
echo >> configure.log
# check for strerror() for use by gz* functions
cat > $test.c <<EOF
#include <string.h>
#include <errno.h>
int main() { return strlen(strerror(errno)); }
EOF
if try $CC $CFLAGS -o $test $test.c; then
echo "Checking for strerror... Yes." | tee -a configure.log
else
CFLAGS="${CFLAGS} -DNO_STRERROR"
SFLAGS="${SFLAGS} -DNO_STRERROR"
echo "Checking for strerror... No." | tee -a configure.log
fi
# copy clean zconf.h for subsequent edits
cp -p zconf.h.in zconf.h
echo >> configure.log
# check for unistd.h and save result in zconf.h
cat > $test.c <<EOF
#include <unistd.h>
int main() { return 0; }
EOF
if try $CC -c $CFLAGS $test.c; then
sed < zconf.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be/ 1\1 was/" > zconf.temp.h
mv zconf.temp.h zconf.h
echo "Checking for unistd.h... Yes." | tee -a configure.log
else
echo "Checking for unistd.h... No." | tee -a configure.log
fi
echo >> configure.log
# check for stdarg.h and save result in zconf.h
cat > $test.c <<EOF
#include <stdarg.h>
int main() { return 0; }
EOF
if try $CC -c $CFLAGS $test.c; then
sed < zconf.h "/^#ifdef HAVE_STDARG_H.* may be/s/def HAVE_STDARG_H\(.*\) may be/ 1\1 was/" > zconf.temp.h
mv zconf.temp.h zconf.h
echo "Checking for stdarg.h... Yes." | tee -a configure.log
else
echo "Checking for stdarg.h... No." | tee -a configure.log
fi
# if the z_ prefix was requested, save that in zconf.h
if test $zprefix -eq 1; then
sed < zconf.h "/#ifdef Z_PREFIX.* may be/s/def Z_PREFIX\(.*\) may be/ 1\1 was/" > zconf.temp.h
mv zconf.temp.h zconf.h
echo >> configure.log
echo "Using z_ prefix on all symbols." | tee -a configure.log
fi
# if --solo compilation was requested, save that in zconf.h and remove gz stuff from object lists
if test $solo -eq 1; then
sed '/#define ZCONF_H/a\
#define Z_SOLO
' < zconf.h > zconf.temp.h
mv zconf.temp.h zconf.h
OBJC='$(OBJZ)'
PIC_OBJC='$(PIC_OBJZ)'
fi
# if code coverage testing was requested, use older gcc if defined, e.g. "gcc-4.2" on Mac OS X
if test $cover -eq 1; then
CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage"
if test -n "$GCC_CLASSIC"; then
CC=$GCC_CLASSIC
fi
fi
echo >> configure.log
# conduct a series of tests to resolve eight possible cases of using "vs" or "s" printf functions
# (using stdarg or not), with or without "n" (proving size of buffer), and with or without a
# return value. The most secure result is vsnprintf() with a return value. snprintf() with a
# return value is secure as well, but then gzprintf() will be limited to 20 arguments.
cat > $test.c <<EOF
#include <stdio.h>
#include <stdarg.h>
#include "zconf.h"
int main()
{
#ifndef STDC
choke me
#endif
return 0;
}
EOF
if try $CC -c $CFLAGS $test.c; then
echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()." | tee -a configure.log
echo >> configure.log
cat > $test.c <<EOF
#include <stdio.h>
#include <stdarg.h>
int mytest(const char *fmt, ...)
{
char buf[20];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return 0;
}
int main()
{
return (mytest("Hello%d\n", 1));
}
EOF
if try $CC $CFLAGS -o $test $test.c; then
echo "Checking for vsnprintf() in stdio.h... Yes." | tee -a configure.log
echo >> configure.log
cat >$test.c <<EOF
#include <stdio.h>
#include <stdarg.h>
int mytest(const char *fmt, ...)
{
int n;
char buf[20];
va_list ap;
va_start(ap, fmt);
n = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return n;
}
int main()
{
return (mytest("Hello%d\n", 1));
}
EOF
if try $CC -c $CFLAGS $test.c; then
echo "Checking for return value of vsnprintf()... Yes." | tee -a configure.log
else
CFLAGS="$CFLAGS -DHAS_vsnprintf_void"
SFLAGS="$SFLAGS -DHAS_vsnprintf_void"
echo "Checking for return value of vsnprintf()... No." | tee -a configure.log
echo " WARNING: apparently vsnprintf() does not return a value. zlib" | tee -a configure.log
echo " can build but will be open to possible string-format security" | tee -a configure.log
echo " vulnerabilities." | tee -a configure.log
fi
else
CFLAGS="$CFLAGS -DNO_vsnprintf"
SFLAGS="$SFLAGS -DNO_vsnprintf"
echo "Checking for vsnprintf() in stdio.h... No." | tee -a configure.log
echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" | tee -a configure.log
echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log
echo " vulnerabilities." | tee -a configure.log
echo >> configure.log
cat >$test.c <<EOF
#include <stdio.h>
#include <stdarg.h>
int mytest(const char *fmt, ...)
{
int n;
char buf[20];
va_list ap;
va_start(ap, fmt);
n = vsprintf(buf, fmt, ap);
va_end(ap);
return n;
}
int main()
{
return (mytest("Hello%d\n", 1));
}
EOF
if try $CC -c $CFLAGS $test.c; then
echo "Checking for return value of vsprintf()... Yes." | tee -a configure.log
else
CFLAGS="$CFLAGS -DHAS_vsprintf_void"
SFLAGS="$SFLAGS -DHAS_vsprintf_void"
echo "Checking for return value of vsprintf()... No." | tee -a configure.log
echo " WARNING: apparently vsprintf() does not return a value. zlib" | tee -a configure.log
echo " can build but will be open to possible string-format security" | tee -a configure.log
echo " vulnerabilities." | tee -a configure.log
fi
fi
else
echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()." | tee -a configure.log
echo >> configure.log
cat >$test.c <<EOF
#include <stdio.h>
int mytest()
{
char buf[20];
snprintf(buf, sizeof(buf), "%s", "foo");
return 0;
}
int main()
{
return (mytest());
}
EOF
if try $CC $CFLAGS -o $test $test.c; then
echo "Checking for snprintf() in stdio.h... Yes." | tee -a configure.log
echo >> configure.log
cat >$test.c <<EOF
#include <stdio.h>
int mytest()
{
char buf[20];
return snprintf(buf, sizeof(buf), "%s", "foo");
}
int main()
{
return (mytest());
}
EOF
if try $CC -c $CFLAGS $test.c; then
echo "Checking for return value of snprintf()... Yes." | tee -a configure.log
else
CFLAGS="$CFLAGS -DHAS_snprintf_void"
SFLAGS="$SFLAGS -DHAS_snprintf_void"
echo "Checking for return value of snprintf()... No." | tee -a configure.log
echo " WARNING: apparently snprintf() does not return a value. zlib" | tee -a configure.log
echo " can build but will be open to possible string-format security" | tee -a configure.log
echo " vulnerabilities." | tee -a configure.log
fi
else
CFLAGS="$CFLAGS -DNO_snprintf"
SFLAGS="$SFLAGS -DNO_snprintf"
echo "Checking for snprintf() in stdio.h... No." | tee -a configure.log
echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" | tee -a configure.log
echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log
echo " vulnerabilities." | tee -a configure.log
echo >> configure.log
cat >$test.c <<EOF
#include <stdio.h>
int mytest()
{
char buf[20];
return sprintf(buf, "%s", "foo");
}
int main()
{
return (mytest());
}
EOF
if try $CC -c $CFLAGS $test.c; then
echo "Checking for return value of sprintf()... Yes." | tee -a configure.log
else
CFLAGS="$CFLAGS -DHAS_sprintf_void"
SFLAGS="$SFLAGS -DHAS_sprintf_void"
echo "Checking for return value of sprintf()... No." | tee -a configure.log
echo " WARNING: apparently sprintf() does not return a value. zlib" | tee -a configure.log
echo " can build but will be open to possible string-format security" | tee -a configure.log
echo " vulnerabilities." | tee -a configure.log
fi
fi
fi
# see if we can hide zlib internal symbols that are linked between separate source files
if test "$gcc" -eq 1; then
echo >> configure.log
cat > $test.c <<EOF
#define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
int ZLIB_INTERNAL foo;
int main()
{
return 0;
}
EOF
if tryboth $CC -c $CFLAGS $test.c; then
CFLAGS="$CFLAGS -DHAVE_HIDDEN"
SFLAGS="$SFLAGS -DHAVE_HIDDEN"
echo "Checking for attribute(visibility) support... Yes." | tee -a configure.log
else
echo "Checking for attribute(visibility) support... No." | tee -a configure.log
fi
fi
# show the results in the log
echo >> configure.log
echo ALL = $ALL >> configure.log
echo AR = $AR >> configure.log
echo ARFLAGS = $ARFLAGS >> configure.log
echo CC = $CC >> configure.log
echo CFLAGS = $CFLAGS >> configure.log
echo CPP = $CPP >> configure.log
echo EXE = $EXE >> configure.log
echo LDCONFIG = $LDCONFIG >> configure.log
echo LDFLAGS = $LDFLAGS >> configure.log
echo LDSHARED = $LDSHARED >> configure.log
echo LDSHAREDLIBC = $LDSHAREDLIBC >> configure.log
echo OBJC = $OBJC >> configure.log
echo PIC_OBJC = $PIC_OBJC >> configure.log
echo RANLIB = $RANLIB >> configure.log
echo SFLAGS = $SFLAGS >> configure.log
echo SHAREDLIB = $SHAREDLIB >> configure.log
echo SHAREDLIBM = $SHAREDLIBM >> configure.log
echo SHAREDLIBV = $SHAREDLIBV >> configure.log
echo STATICLIB = $STATICLIB >> configure.log
echo TEST = $TEST >> configure.log
echo VER = $VER >> configure.log
echo Z_U4 = $Z_U4 >> configure.log
echo exec_prefix = $exec_prefix >> configure.log
echo includedir = $includedir >> configure.log
echo libdir = $libdir >> configure.log
echo mandir = $mandir >> configure.log
echo prefix = $prefix >> configure.log
echo sharedlibdir = $sharedlibdir >> configure.log
echo uname = $uname >> configure.log
# udpate Makefile with the configure results
sed < Makefile.in "
/^CC *=/s#=.*#=$CC#
/^CFLAGS *=/s#=.*#=$CFLAGS#
/^SFLAGS *=/s#=.*#=$SFLAGS#
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
/^LDSHARED *=/s#=.*#=$LDSHARED#
/^CPP *=/s#=.*#=$CPP#
/^STATICLIB *=/s#=.*#=$STATICLIB#
/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
/^AR *=/s#=.*#=$AR#
/^ARFLAGS *=/s#=.*#=$ARFLAGS#
/^RANLIB *=/s#=.*#=$RANLIB#
/^LDCONFIG *=/s#=.*#=$LDCONFIG#
/^LDSHAREDLIBC *=/s#=.*#=$LDSHAREDLIBC#
/^EXE *=/s#=.*#=$EXE#
/^prefix *=/s#=.*#=$prefix#
/^exec_prefix *=/s#=.*#=$exec_prefix#
/^libdir *=/s#=.*#=$libdir#
/^sharedlibdir *=/s#=.*#=$sharedlibdir#
/^includedir *=/s#=.*#=$includedir#
/^mandir *=/s#=.*#=$mandir#
/^OBJC *=/s#=.*#= $OBJC#
/^PIC_OBJC *=/s#=.*#= $PIC_OBJC#
/^all: */s#:.*#: $ALL#
/^test: */s#:.*#: $TEST#
" > Makefile
# create zlib.pc with the configure results
sed < zlib.pc.in "
/^CC *=/s#=.*#=$CC#
/^CFLAGS *=/s#=.*#=$CFLAGS#
/^CPP *=/s#=.*#=$CPP#
/^LDSHARED *=/s#=.*#=$LDSHARED#
/^STATICLIB *=/s#=.*#=$STATICLIB#
/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
/^AR *=/s#=.*#=$AR#
/^ARFLAGS *=/s#=.*#=$ARFLAGS#
/^RANLIB *=/s#=.*#=$RANLIB#
/^EXE *=/s#=.*#=$EXE#
/^prefix *=/s#=.*#=$prefix#
/^exec_prefix *=/s#=.*#=$exec_prefix#
/^libdir *=/s#=.*#=$libdir#
/^sharedlibdir *=/s#=.*#=$sharedlibdir#
/^includedir *=/s#=.*#=$includedir#
/^mandir *=/s#=.*#=$mandir#
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
" | sed -e "
s/\@VERSION\@/$VER/g;
" > zlib.pc
# done
leave 0

View File

@@ -0,0 +1,78 @@
All files under this contrib directory are UNSUPPORTED. There were
provided by users of zlib and were not tested by the authors of zlib.
Use at your own risk. Please contact the authors of the contributions
for help about these, not the zlib authors. Thanks.
ada/ by Dmitriy Anisimkov <anisimkov@yahoo.com>
Support for Ada
See http://zlib-ada.sourceforge.net/
amd64/ by Mikhail Teterin <mi@ALDAN.algebra.com>
asm code for AMD64
See patch at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/96393
asm686/ by Brian Raiter <breadbox@muppetlabs.com>
asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax
See http://www.muppetlabs.com/~breadbox/software/assembly.html
blast/ by Mark Adler <madler@alumni.caltech.edu>
Decompressor for output of PKWare Data Compression Library (DCL)
delphi/ by Cosmin Truta <cosmint@cs.ubbcluj.ro>
Support for Delphi and C++ Builder
dotzlib/ by Henrik Ravn <henrik@ravn.com>
Support for Microsoft .Net and Visual C++ .Net
gcc_gvmat64/by Gilles Vollant <info@winimage.com>
GCC Version of x86 64-bit (AMD64 and Intel EM64t) code for x64
assembler to replace longest_match() and inflate_fast()
infback9/ by Mark Adler <madler@alumni.caltech.edu>
Unsupported diffs to infback to decode the deflate64 format
inflate86/ by Chris Anderson <christop@charm.net>
Tuned x86 gcc asm code to replace inflate_fast()
iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
A C++ I/O streams interface to the zlib gz* functions
iostream2/ by Tyge L<>vset <Tyge.Lovset@cmr.no>
Another C++ I/O streams interface
iostream3/ by Ludwig Schwardt <schwardt@sun.ac.za>
and Kevin Ruland <kevin@rodin.wustl.edu>
Yet another C++ I/O streams interface
masmx64/ by Gilles Vollant <info@winimage.com>
x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to
replace longest_match() and inflate_fast(), also masm x86
64-bits translation of Chris Anderson inflate_fast()
masmx86/ by Gilles Vollant <info@winimage.com>
x86 asm code to replace longest_match() and inflate_fast(),
for Visual C++ and MASM (32 bits).
Based on Brian Raiter (asm686) and Chris Anderson (inflate86)
minizip/ by Gilles Vollant <info@winimage.com>
Mini zip and unzip based on zlib
Includes Zip64 support by Mathias Svensson <mathias@result42.com>
See http://www.winimage.com/zLibDll/unzip.html
pascal/ by Bob Dellaca <bobdl@xtra.co.nz> et al.
Support for Pascal
puff/ by Mark Adler <madler@alumni.caltech.edu>
Small, low memory usage inflate. Also serves to provide an
unambiguous description of the deflate format.
testzlib/ by Gilles Vollant <info@winimage.com>
Example of the use of zlib
untgz/ by Pedro A. Aranda Gutierrez <paag@tid.es>
A very simple tar.gz file extractor using zlib
vstudio/ by Gilles Vollant <info@winimage.com>
Building a minizip-enhanced zlib with Microsoft Visual Studio
Includes vc11 from kreuzerkrieg and vc12 from davispuh

View File

@@ -0,0 +1,106 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2004 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
--
-- $Id: buffer_demo.adb,v 1.3 2004/09/06 06:55:35 vagul Exp $
-- This demo program provided by Dr Steve Sangwine <sjs@essex.ac.uk>
--
-- Demonstration of a problem with Zlib-Ada (already fixed) when a buffer
-- of exactly the correct size is used for decompressed data, and the last
-- few bytes passed in to Zlib are checksum bytes.
-- This program compresses a string of text, and then decompresses the
-- compressed text into a buffer of the same size as the original text.
with Ada.Streams; use Ada.Streams;
with Ada.Text_IO;
with ZLib; use ZLib;
procedure Buffer_Demo is
EOL : Character renames ASCII.LF;
Text : constant String
:= "Four score and seven years ago our fathers brought forth," & EOL &
"upon this continent, a new nation, conceived in liberty," & EOL &
"and dedicated to the proposition that `all men are created equal'.";
Source : Stream_Element_Array (1 .. Text'Length);
for Source'Address use Text'Address;
begin
Ada.Text_IO.Put (Text);
Ada.Text_IO.New_Line;
Ada.Text_IO.Put_Line
("Uncompressed size : " & Positive'Image (Text'Length) & " bytes");
declare
Compressed_Data : Stream_Element_Array (1 .. Text'Length);
L : Stream_Element_Offset;
begin
Compress : declare
Compressor : Filter_Type;
I : Stream_Element_Offset;
begin
Deflate_Init (Compressor);
-- Compress the whole of T at once.
Translate (Compressor, Source, I, Compressed_Data, L, Finish);
pragma Assert (I = Source'Last);
Close (Compressor);
Ada.Text_IO.Put_Line
("Compressed size : "
& Stream_Element_Offset'Image (L) & " bytes");
end Compress;
-- Now we decompress the data, passing short blocks of data to Zlib
-- (because this demonstrates the problem - the last block passed will
-- contain checksum information and there will be no output, only a
-- check inside Zlib that the checksum is correct).
Decompress : declare
Decompressor : Filter_Type;
Uncompressed_Data : Stream_Element_Array (1 .. Text'Length);
Block_Size : constant := 4;
-- This makes sure that the last block contains
-- only Adler checksum data.
P : Stream_Element_Offset := Compressed_Data'First - 1;
O : Stream_Element_Offset;
begin
Inflate_Init (Decompressor);
loop
Translate
(Decompressor,
Compressed_Data
(P + 1 .. Stream_Element_Offset'Min (P + Block_Size, L)),
P,
Uncompressed_Data
(Total_Out (Decompressor) + 1 .. Uncompressed_Data'Last),
O,
No_Flush);
Ada.Text_IO.Put_Line
("Total in : " & Count'Image (Total_In (Decompressor)) &
", out : " & Count'Image (Total_Out (Decompressor)));
exit when P = L;
end loop;
Ada.Text_IO.New_Line;
Ada.Text_IO.Put_Line
("Decompressed text matches original text : "
& Boolean'Image (Uncompressed_Data = Source));
end Decompress;
end;
end Buffer_Demo;

View File

@@ -0,0 +1,156 @@
----------------------------------------------------------------
-- ZLib for Ada thick binding. --
-- --
-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
-- --
-- Open source license information is in the zlib.ads file. --
----------------------------------------------------------------
-- Continuous test for ZLib multithreading. If the test would fail
-- we should provide thread safe allocation routines for the Z_Stream.
--
-- $Id: mtest.adb,v 1.4 2004/07/23 07:49:54 vagul Exp $
with ZLib;
with Ada.Streams;
with Ada.Numerics.Discrete_Random;
with Ada.Text_IO;
with Ada.Exceptions;
with Ada.Task_Identification;
procedure MTest is
use Ada.Streams;
use ZLib;
Stop : Boolean := False;
pragma Atomic (Stop);
subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#;
package Random_Elements is
new Ada.Numerics.Discrete_Random (Visible_Symbols);
task type Test_Task;
task body Test_Task is
Buffer : Stream_Element_Array (1 .. 100_000);
Gen : Random_Elements.Generator;
Buffer_First : Stream_Element_Offset;
Compare_First : Stream_Element_Offset;
Deflate : Filter_Type;
Inflate : Filter_Type;
procedure Further (Item : in Stream_Element_Array);
procedure Read_Buffer
(Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset);
-------------
-- Further --
-------------
procedure Further (Item : in Stream_Element_Array) is
procedure Compare (Item : in Stream_Element_Array);
-------------
-- Compare --
-------------
procedure Compare (Item : in Stream_Element_Array) is
Next_First : Stream_Element_Offset := Compare_First + Item'Length;
begin
if Buffer (Compare_First .. Next_First - 1) /= Item then
raise Program_Error;
end if;
Compare_First := Next_First;
end Compare;
procedure Compare_Write is new ZLib.Write (Write => Compare);
begin
Compare_Write (Inflate, Item, No_Flush);
end Further;
-----------------
-- Read_Buffer --
-----------------
procedure Read_Buffer
(Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset)
is
Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First;
Next_First : Stream_Element_Offset;
begin
if Item'Length <= Buff_Diff then
Last := Item'Last;
Next_First := Buffer_First + Item'Length;
Item := Buffer (Buffer_First .. Next_First - 1);
Buffer_First := Next_First;
else
Last := Item'First + Buff_Diff;
Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last);
Buffer_First := Buffer'Last + 1;
end if;
end Read_Buffer;
procedure Translate is new Generic_Translate
(Data_In => Read_Buffer,
Data_Out => Further);
begin
Random_Elements.Reset (Gen);
Buffer := (others => 20);
Main : loop
for J in Buffer'Range loop
Buffer (J) := Random_Elements.Random (Gen);
Deflate_Init (Deflate);
Inflate_Init (Inflate);
Buffer_First := Buffer'First;
Compare_First := Buffer'First;
Translate (Deflate);
if Compare_First /= Buffer'Last + 1 then
raise Program_Error;
end if;
Ada.Text_IO.Put_Line
(Ada.Task_Identification.Image
(Ada.Task_Identification.Current_Task)
& Stream_Element_Offset'Image (J)
& ZLib.Count'Image (Total_Out (Deflate)));
Close (Deflate);
Close (Inflate);
exit Main when Stop;
end loop;
end loop Main;
exception
when E : others =>
Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E));
Stop := True;
end Test_Task;
Test : array (1 .. 4) of Test_Task;
pragma Unreferenced (Test);
Dummy : Character;
begin
Ada.Text_IO.Get_Immediate (Dummy);
Stop := True;
end MTest;

Some files were not shown because too many files have changed in this diff Show More