mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Merge subtree Beast 1.0.0-b6:
Merge commit '999e2fa0318b5982736d3ea01a418770ea802671'
This commit is contained in:
@@ -296,7 +296,9 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\detail\stream_concepts.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\detail\write_streambuf.hpp">
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\detail\write_dynabuf.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\dynabuf_readstream.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\error.hpp">
|
||||
</ClInclude>
|
||||
@@ -308,12 +310,12 @@
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\consuming_buffers.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\dynabuf_readstream.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\prepare_buffers.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\static_streambuf.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\streambuf_readstream.ipp">
|
||||
</None>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\placeholders.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\prepare_buffers.hpp">
|
||||
@@ -324,16 +326,16 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\streambuf.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\streambuf_readstream.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\stream_concepts.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\to_string.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\write_streambuf.hpp">
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\write_dynabuf.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\basic_dynabuf_body.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\basic_headers.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\basic_parser_v1.hpp">
|
||||
@@ -348,6 +350,8 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\detail\has_content_length.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\detail\rfc7230.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\empty_body.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\headers.hpp">
|
||||
@@ -360,6 +364,8 @@
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\http\impl\read.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\http\impl\rfc7230.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\http\impl\write.ipp">
|
||||
</None>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\message.hpp">
|
||||
@@ -376,8 +382,6 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\resume_context.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\rfc2616.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\rfc7230.hpp">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\streambuf_body.hpp">
|
||||
|
||||
@@ -627,9 +627,12 @@
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\detail\stream_concepts.hpp">
|
||||
<Filter>include\beast\core\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\detail\write_streambuf.hpp">
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\detail\write_dynabuf.hpp">
|
||||
<Filter>include\beast\core\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\dynabuf_readstream.hpp">
|
||||
<Filter>include\beast\core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\error.hpp">
|
||||
<Filter>include\beast\core</Filter>
|
||||
</ClInclude>
|
||||
@@ -645,15 +648,15 @@
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\consuming_buffers.ipp">
|
||||
<Filter>include\beast\core\impl</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\dynabuf_readstream.ipp">
|
||||
<Filter>include\beast\core\impl</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\prepare_buffers.ipp">
|
||||
<Filter>include\beast\core\impl</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\static_streambuf.ipp">
|
||||
<Filter>include\beast\core\impl</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\core\impl\streambuf_readstream.ipp">
|
||||
<Filter>include\beast\core\impl</Filter>
|
||||
</None>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\placeholders.hpp">
|
||||
<Filter>include\beast\core</Filter>
|
||||
</ClInclude>
|
||||
@@ -669,21 +672,21 @@
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\streambuf.hpp">
|
||||
<Filter>include\beast\core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\streambuf_readstream.hpp">
|
||||
<Filter>include\beast\core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\stream_concepts.hpp">
|
||||
<Filter>include\beast\core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\to_string.hpp">
|
||||
<Filter>include\beast\core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\write_streambuf.hpp">
|
||||
<ClInclude Include="..\..\src\beast\include\beast\core\write_dynabuf.hpp">
|
||||
<Filter>include\beast\core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http.hpp">
|
||||
<Filter>include\beast</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\basic_dynabuf_body.hpp">
|
||||
<Filter>include\beast\http</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\basic_headers.hpp">
|
||||
<Filter>include\beast\http</Filter>
|
||||
</ClInclude>
|
||||
@@ -705,6 +708,9 @@
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\detail\has_content_length.hpp">
|
||||
<Filter>include\beast\http\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\detail\rfc7230.hpp">
|
||||
<Filter>include\beast\http\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\empty_body.hpp">
|
||||
<Filter>include\beast\http</Filter>
|
||||
</ClInclude>
|
||||
@@ -723,6 +729,9 @@
|
||||
<None Include="..\..\src\beast\include\beast\http\impl\read.ipp">
|
||||
<Filter>include\beast\http\impl</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\http\impl\rfc7230.ipp">
|
||||
<Filter>include\beast\http\impl</Filter>
|
||||
</None>
|
||||
<None Include="..\..\src\beast\include\beast\http\impl\write.ipp">
|
||||
<Filter>include\beast\http\impl</Filter>
|
||||
</None>
|
||||
@@ -747,9 +756,6 @@
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\resume_context.hpp">
|
||||
<Filter>include\beast\http</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\rfc2616.hpp">
|
||||
<Filter>include\beast\http</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\include\beast\http\rfc7230.hpp">
|
||||
<Filter>include\beast\http</Filter>
|
||||
</ClInclude>
|
||||
|
||||
4
src/beast/.gitignore
vendored
4
src/beast/.gitignore
vendored
@@ -24,3 +24,7 @@ contents.xcworkspacedata
|
||||
.svn
|
||||
profile
|
||||
bin/
|
||||
node_modules/
|
||||
cov-int/
|
||||
nohup.out
|
||||
venv/
|
||||
|
||||
@@ -14,13 +14,6 @@ env:
|
||||
packages: &gcc5_pkgs
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# - gcc-5-multilib
|
||||
# - g++-5-multilib
|
||||
# - gcc-multilib
|
||||
# - g++-multilib
|
||||
# - libgd2-xpm
|
||||
# - ia32-libs
|
||||
# - ia32-libs-multiarch
|
||||
- python-software-properties
|
||||
- libssl-dev
|
||||
- libffi-dev
|
||||
@@ -52,20 +45,7 @@ packages: &clang38_pkgs
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# GCC/Debug
|
||||
# - compiler: gcc
|
||||
# env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=64
|
||||
# addons: &ao_gcc5
|
||||
# apt:
|
||||
# sources: ['ubuntu-toolchain-r-test']
|
||||
# packages: *gcc5_pkgs
|
||||
|
||||
# # GCC/Release
|
||||
# - compiler: gcc
|
||||
# env: GCC_VER=5 VARIANT=release ADDRESS_MODEL=64
|
||||
# addons: *ao_gcc5
|
||||
|
||||
# Coverage
|
||||
# GCC/Coverage
|
||||
- compiler: gcc
|
||||
env: GCC_VER=5 VARIANT=coverage ADDRESS_MODEL=64
|
||||
addons: &ao_gcc5
|
||||
@@ -73,36 +53,25 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: *gcc5_pkgs
|
||||
|
||||
# # Clang/Debug
|
||||
# - compiler: clang
|
||||
# env: GCC_VER=5 VARIANT=debug CLANG_VER=3.8 ADDRESS_MODEL=64
|
||||
# addons: &ao_clang38
|
||||
# apt:
|
||||
# sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
|
||||
# packages: *clang38_pkgs
|
||||
# # GCC/Debug
|
||||
# - compiler: gcc
|
||||
# env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=64
|
||||
# addons: *ao_gcc5
|
||||
# branches: # NOTE: this does NOT work, though it SHOULD
|
||||
# - master
|
||||
# - develop
|
||||
|
||||
# # Clang/Release
|
||||
# - compiler: clang
|
||||
# env: GCC_VER=5 VARIANT=release CLANG_VER=3.8 ADDRESS_MODEL=64
|
||||
# addons: *ao_clang38
|
||||
|
||||
# Clang/AddressSanitizer
|
||||
# Clang/UndefinedBehaviourSanitizer
|
||||
- compiler: clang
|
||||
env: GCC_VER=5 VARIANT=asan CLANG_VER=3.8 ADDRESS_MODEL=64
|
||||
env: GCC_VER=5 VARIANT=usan CLANG_VER=3.8 ADDRESS_MODEL=64 UBSAN_OPTIONS='print_stacktrace=1'
|
||||
addons: &ao_clang38
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
|
||||
packages: *clang38_pkgs
|
||||
|
||||
# Clang/MemorySanitizer
|
||||
# VFALCO Generates false positives unless libc++ is compiled with msan turned on
|
||||
#- compiler: clang
|
||||
# env: GCC_VER=5 VARIANT=msan CLANG_VER=3.8 ADDRESS_MODEL=64 MSAN_OPTIONS=poison_in_dtor=1,sanitize-memory-track-origins=2
|
||||
# addons: *ao_clang38
|
||||
|
||||
# Clang/UndefinedBehaviourSanitizer
|
||||
# Clang/AddressSanitizer
|
||||
- compiler: clang
|
||||
env: GCC_VER=5 VARIANT=usan CLANG_VER=3.8 ADDRESS_MODEL=64
|
||||
env: GCC_VER=5 VARIANT=asan CLANG_VER=3.8 ADDRESS_MODEL=64
|
||||
addons: *ao_clang38
|
||||
|
||||
cache:
|
||||
|
||||
21
src/beast/CHANGELOG
Normal file
21
src/beast/CHANGELOG
Normal file
@@ -0,0 +1,21 @@
|
||||
1.0.0-b6
|
||||
|
||||
* Use SFINAE on return values
|
||||
* Use beast::error_code instead of nested types
|
||||
* Tidy up use of GENERATING_DOCS
|
||||
* Remove obsolete RFC2616 functions
|
||||
* Add message swap members and free functions
|
||||
* Add HTTP field value parser containers: ext_list, param_list, token_list
|
||||
* Fixes for some corner cases in basic_parser_v1
|
||||
* Configurable limits on headers and body sizes in basic_parser_v1
|
||||
|
||||
API Changes:
|
||||
|
||||
* ci_equal is moved to beast::http namespace, in rfc7230.hpp
|
||||
|
||||
* "DynamicBuffer","dynabuf" renamed from "Streambuf", "streambuf". See:
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4478.html#requirements.dynamic_buffers
|
||||
|
||||
* basic_parser_v1 adheres to rfc7230 as strictly as possible
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@@ -1,7 +1,9 @@
|
||||
# Beast
|
||||
|
||||
[](https://travis-ci.org/vinniefalco/Beast) [![codecov]
|
||||
(https://codecov.io/gh/vinniefalco/Beast/branch/master/graph/badge.svg)](https://codecov.io/gh/vinniefalco/Beast) [![Documentation]
|
||||
[](https://gitter.im/vinniefalco/Beast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status]
|
||||
(https://travis-ci.org/vinniefalco/Beast.svg?branch=master)](https://travis-ci.org/vinniefalco/Beast) [![codecov]
|
||||
(https://codecov.io/gh/vinniefalco/Beast/branch/master/graph/badge.svg)](https://codecov.io/gh/vinniefalco/Beast) [![coveralls]
|
||||
(https://coveralls.io/repos/github/vinniefalco/Beast/badge.svg?branch=master)](https://coveralls.io/github/vinniefalco/Beast?branch=master) [![Documentation]
|
||||
(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/) [![License]
|
||||
(https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
|
||||
|
||||
@@ -14,6 +16,11 @@ Requirements:
|
||||
* C++11 or greater
|
||||
* OpenSSL (optional)
|
||||
|
||||
This software is currently in beta: interfaces are subject to change. For
|
||||
recent changes see [CHANGELOG](CHANGELOG).
|
||||
The library has been submitted to the
|
||||
[Boost Library Incubator](http://rrsd.com/blincubator.com/bi_library/beast-2/?gform_post_id=1579)
|
||||
|
||||
Example WebSocket program:
|
||||
```C++
|
||||
#include <beast/to_string.hpp>
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
* Add writer::prepare(msg&) interface to set Content-Type
|
||||
|
||||
General:
|
||||
* Use SFINAE on return values (search for "class =")
|
||||
* Remove http,websocket error_code types and use the one in <beast/error.hpp>
|
||||
|
||||
Boost.Http
|
||||
* Use enum instead of bool in isRequest
|
||||
* move version to a subclass of message
|
||||
|
||||
Docs:
|
||||
* Include Example program listings in the docs
|
||||
* Fix index in docs
|
||||
* Figure out why namespace rfc2616 is included in docs
|
||||
(currently disabled via GENERATING_DOCS macro)
|
||||
* melpon sandbox?
|
||||
* Check DOXYGEN, GENERATIC_DOCS directives in source
|
||||
- See if we can include them now that xsl is fixed
|
||||
* Implement cleanup-param to remove spaces around template arguments
|
||||
e.g. in basic_streambuf move constructor members
|
||||
* Don't put using namespace at file scope in examples,
|
||||
@@ -27,15 +18,12 @@ Core:
|
||||
* Complete allocator testing in basic_streambuf
|
||||
|
||||
WebSocket:
|
||||
* more invokable unit test coverage
|
||||
* More control over the HTTP request and response during handshakes
|
||||
* optimized versions of key/masking, choose prepared_key size
|
||||
* invokable unit test
|
||||
* Don't try to read requests into empty_body
|
||||
* Give callers control over the http request/response used during handshake
|
||||
* Investigate poor autobahn results in Debug builds
|
||||
* Fall through composed operation switch cases
|
||||
* Replace stream::error_ with stream::state_, example states: ok, error, abort_io
|
||||
Need a cancel state so waking up a ping stored in invokable knows to call the
|
||||
final handler with operation_aborted
|
||||
* Use close_code::no_code instead of close_code::none
|
||||
* Make request_type, response_type public APIs,
|
||||
use in stream member function signatures
|
||||
@@ -44,24 +32,25 @@ HTTP:
|
||||
* Define Parser concept in HTTP
|
||||
- Need parse version of read() so caller can set parser options
|
||||
like maximum size of headers, maximum body size, etc
|
||||
* trim public interface of rfc2616.h to essentials only
|
||||
* add bool should_close(message_v1 const&) to replace the use
|
||||
of eof return value from write and async_write
|
||||
* http type_check, e.g. is_WritableBody
|
||||
* More fine grained parser errors
|
||||
* HTTP parser size limit with test (configurable?)
|
||||
* HTTP parser trailers with test
|
||||
* Decode chunk encoding parameters
|
||||
* URL parser, strong URL character checking in HTTP parser
|
||||
* Update for rfc7230
|
||||
* Consider rename to MessageBody concept
|
||||
* Fix prepare() calling content_length() without init()
|
||||
* Use construct,destroy allocator routines in basic_headers
|
||||
* Complete allocator testing in basic_streambuf, basic_headers
|
||||
* Add tests for writer using the resume function / coros
|
||||
* Custom HTTP error codes for various situations
|
||||
* Make empty_body write-only, remove reader nested type
|
||||
* Add concepts WritableBody ReadableBody with type checks,
|
||||
check them in read and write functions
|
||||
* Branch prediction hints in parser
|
||||
* Check basic_parser_v1 against rfc7230 for leading message whitespace
|
||||
* Fix the order of message constructor parameters:
|
||||
body first then headers (since body is constructed with arguments more often)
|
||||
* Unit tests for char tables
|
||||
* Remove status_code() from API when isRequest==true, et. al.
|
||||
* Permit sending trailers and parameters in chunk-encoding chunks
|
||||
|
||||
Future:
|
||||
|
||||
* SOCKS proxy client and server implementations
|
||||
|
||||
|
||||
@@ -192,11 +192,11 @@ supporting its development.
|
||||
[section:types Type Requirements]
|
||||
[include types/Body.qbk]
|
||||
[include types/BufferSequence.qbk]
|
||||
[include types/DynamicBuffer.qbk]
|
||||
[include types/Field.qbk]
|
||||
[include types/FieldSequence.qbk]
|
||||
[include types/Parser.qbk]
|
||||
[include types/Reader.qbk]
|
||||
[include types/Streambuf.qbk]
|
||||
[include types/Streams.qbk]
|
||||
[include types/Writer.qbk]
|
||||
[endsect]
|
||||
|
||||
@@ -25,13 +25,13 @@ libraries:
|
||||
* Let library users make the important decisions such as how to
|
||||
allocate memory or how to leverage flow control.
|
||||
|
||||
Beast formalizes the [link beast.types.Streambuf [*`Streambuf`]] concept,
|
||||
and relies heavily on the Boost.Asio [*`ConstBufferSequence`] and
|
||||
[*`MutableBufferSequence`] concepts for passing buffers to functions.
|
||||
The authors have found the `Streambuf` and buffer sequence interfaces
|
||||
to be optimal for interacting with Asio, and for other tasks such as
|
||||
incremental parsing of data in buffers (for example, parsing websocket
|
||||
frames stored in a [link beast.ref.static_streambuf `static_streambuf`]).
|
||||
Beast uses the [link beast.types.DynamicBuffer [*`DynamicBuffer`]] concept
|
||||
presented in the Netwoking TS, and relies heavily on the Boost.Asio
|
||||
[*`ConstBufferSequence`] and [*`MutableBufferSequence`] concepts for passing
|
||||
buffers to functions. The authors have found the dynamic buffer and buffer
|
||||
sequence interfaces to be optimal for interacting with Asio, and for other
|
||||
tasks such as incremental parsing of data in buffers (for example, parsing
|
||||
websocket frames stored in a [link beast.ref.static_streambuf `static_streambuf`]).
|
||||
|
||||
During the development of Beast the authors have studied other software
|
||||
packages and in particular the comments left during the Boost Review process
|
||||
|
||||
@@ -182,21 +182,9 @@ used in the examples:
|
||||
resp.body = "Here is the data you requested";
|
||||
```
|
||||
|
||||
* [link beast.ref.http__basic_streambuf_body [*`basic_streambuf_body`:]] A body with a
|
||||
`value_type` of `streambuf`. A streambuf is an efficient storage object which
|
||||
uses multiple octet arrays of varying lengths to represent data. Here is
|
||||
a body that uses a `boost::asio::streambuf` as its container:
|
||||
```
|
||||
template<class ConstBufferSequence>
|
||||
http::response<http::basic_streambuf_body<boost::asio::streambuf>>
|
||||
make_response(ConstBufferSequence const& buffers)
|
||||
{
|
||||
http::response<http::streambuf_body<boost::asio::streambuf>> resp;
|
||||
resp.body.commit(boost::asio::buffer_copy(resp.body.prepare(
|
||||
boost::asio::buffer_size(buffers)), buffers));
|
||||
return resp;
|
||||
}
|
||||
```
|
||||
* [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a
|
||||
`value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage
|
||||
object which uses multiple octet arrays of varying lengths to represent data.
|
||||
|
||||
[heading Sockets]
|
||||
|
||||
@@ -234,7 +222,7 @@ When the implementation reads messages from a socket, it can read bytes lying
|
||||
after the end of the message if they are present (the alternative is to read
|
||||
a single byte at a time which is unsuitable for performance reasons). To
|
||||
store and re-use these extra bytes on subsequent messages, the read interface
|
||||
requires an additional paramter: a [link beast.types.Streambuf [*`Streambuf`]]
|
||||
requires an additional paramter: a [link beast.types.DynamicBuffer [*`DynamicBuffer`]]
|
||||
object. This example reads a message from the socket, with the extra bytes
|
||||
stored in the streambuf parameter for use in a subsequent call to read:
|
||||
```
|
||||
@@ -264,7 +252,7 @@ called:
|
||||
|
||||
An alternative to using a `boost::asio::streambuf` is to use a
|
||||
[link beast.ref.streambuf `beast::streambuf`], which meets the requirements of
|
||||
[*`Streambuf`] and is optimized for performance:
|
||||
[*`DynamicBuffer`] and is optimized for performance:
|
||||
```
|
||||
void handle_read(boost::system::error_code);
|
||||
...
|
||||
@@ -274,7 +262,7 @@ An alternative to using a `boost::asio::streambuf` is to use a
|
||||
```
|
||||
|
||||
The `read` implementation can use any object meeting the requirements of
|
||||
[link beast.types.Streambuf [*`Streambuf`]], allowing callers to define custom
|
||||
[link beast.types.DynamicBuffer [*`DynamicBuffer`]], allowing callers to define custom
|
||||
memory management strategies used by the implementation.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_streambuf_body">basic_streambuf_body</link></member>
|
||||
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
|
||||
<member><link linkend="beast.ref.http__headers">headers</link></member>
|
||||
<member><link linkend="beast.ref.http__message">message</link></member>
|
||||
@@ -39,6 +39,11 @@
|
||||
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
|
||||
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
||||
<member><link linkend="beast.ref.http__headers_max_size">headers_max_size</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
||||
@@ -56,6 +61,7 @@
|
||||
<member><link linkend="beast.ref.http__parse">parse</link></member>
|
||||
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
|
||||
<member><link linkend="beast.ref.http__read">read</link></member>
|
||||
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
||||
<member><link linkend="beast.ref.http__write">write</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
@@ -129,6 +135,7 @@
|
||||
<member><link linkend="beast.ref.basic_streambuf">basic_streambuf</link></member>
|
||||
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
|
||||
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
|
||||
<member><link linkend="beast.ref.dynabuf_readstream">dynabuf_readstream</link></member>
|
||||
<member><link linkend="beast.ref.error_code">error_code</link></member>
|
||||
<member><link linkend="beast.ref.handler_alloc">handler_alloc</link></member>
|
||||
<member><link linkend="beast.ref.prepared_buffers">prepared_buffers</link></member>
|
||||
@@ -136,7 +143,6 @@
|
||||
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
|
||||
<member><link linkend="beast.ref.static_string">static_string</link></member>
|
||||
<member><link linkend="beast.ref.streambuf">streambuf</link></member>
|
||||
<member><link linkend="beast.ref.streambuf_readstream">streambuf_readstream</link></member>
|
||||
<member><link linkend="beast.ref.system_error">system_error</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
@@ -163,8 +169,8 @@
|
||||
<member><link linkend="beast.ref.is_BufferSequence">is_BufferSequence</link></member>
|
||||
<member><link linkend="beast.ref.is_CompletionHandler">is_CompletionHandler</link></member>
|
||||
<member><link linkend="beast.ref.is_ConstBufferSequence">is_ConstBufferSequence</link></member>
|
||||
<member><link linkend="beast.ref.is_DynamicBuffer">is_DynamicBuffer</link></member>
|
||||
<member><link linkend="beast.ref.is_MutableBufferSequence">is_MutableBufferSequence</link></member>
|
||||
<member><link linkend="beast.ref.is_Streambuf">is_Streambuf</link></member>
|
||||
<member><link linkend="beast.ref.is_SyncReadStream">is_SyncReadStream</link></member>
|
||||
<member><link linkend="beast.ref.is_SyncStream">is_SyncStream</link></member>
|
||||
<member><link linkend="beast.ref.is_SyncWriteStream">is_SyncWriteStream</link></member>
|
||||
@@ -173,10 +179,10 @@
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
|
||||
<member><link linkend="beast.types.streams.AsyncStream">AsyncStream</link></member>
|
||||
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
|
||||
<member><link linkend="beast.types.DynamicBuffer">DynamicBuffer</link></member>
|
||||
<member><link linkend="beast.types.streams.Stream">Stream</link></member>
|
||||
<member><link linkend="beast.types.Streambuf">Streambuf</link></member>
|
||||
<member><link linkend="beast.types.streams.SyncStream">SyncStream</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
|
||||
@@ -1552,15 +1552,15 @@
|
||||
<xsl:when test="declname = 'ConstBufferSequence' or type = 'class ConstBufferSequence'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'DynamicBuffer' or type = 'class DynamicBuffer'">
|
||||
<xsl:text>class ``[link beast.types.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'MutableBufferSequence' or type = 'class MutableBufferSequence'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
|
||||
<xsl:text>class ``[link beast.types.streams.Stream [*Stream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Streambuf' or type = 'class Streambuf'">
|
||||
<xsl:text>class ``[link beast.types.Streambuf [*Streambuf]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class SyncStream'">
|
||||
<xsl:text>class ``[link beast.types.streams.SyncStream [*SyncStream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
|
||||
125
src/beast/doc/types/DynamicBuffer.qbk
Normal file
125
src/beast/doc/types/DynamicBuffer.qbk
Normal file
@@ -0,0 +1,125 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 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)
|
||||
]
|
||||
|
||||
[section:DynamicBuffer DynamicBuffer]
|
||||
|
||||
A dynamic buffer encapsulates memory storage that may be automatically resized
|
||||
as required, where the memory is divided into an input sequence followed by an
|
||||
output sequence. These memory regions are internal to the dynamic buffer, but
|
||||
direct access to the elements is provided to permit them to be efficiently used
|
||||
with I/O operations, such as the send or receive operations of a socket. Data
|
||||
written to the output sequence of a dynamic buffer object is appended to the
|
||||
input sequence of the same object.
|
||||
|
||||
The interface to this concept is intended to permit the following
|
||||
implementation strategies:
|
||||
|
||||
* A single contiguous octet array, which is reallocated as necessary to
|
||||
accommodate changes in the size of the octet sequence.
|
||||
|
||||
* A sequence of one or more octet arrays, where each array is of the same
|
||||
size. Additional octet array objects are appended to the sequence to
|
||||
accommodate changes in the size of the octet sequence.
|
||||
|
||||
* A sequence of one or more octet arrays of varying sizes. Additional octet
|
||||
array objects are appended to the sequence to accommodate changes in the
|
||||
size of the character sequence. This is the implementation approached
|
||||
currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
|
||||
|
||||
In the table below:
|
||||
|
||||
* `X` denotes a dynamic buffer class.
|
||||
* `a` denotes a value of type `X`.
|
||||
* `c` denotes a (possibly const) value of type `X`.
|
||||
* `n` denotes a value of type `std::size_t`.
|
||||
* `T` denotes a type meeting the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html `ConstBufferSequence`].
|
||||
* `U` denotes a type meeting the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html `MutableBufferSequence`].
|
||||
|
||||
[table DynamicBuffer requirements
|
||||
[[operation] [type] [semantics, pre/post-conditions]]
|
||||
[
|
||||
[`X::const_buffers_type`]
|
||||
[`T`]
|
||||
[
|
||||
This type represents the memory associated with the input sequence.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`X::mutable_buffers_type`]
|
||||
[`U`]
|
||||
[
|
||||
This type represents the memory associated with the output sequence.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`c.size()`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Returns the size, in bytes, of the input sequence.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`c.max_size()`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Returns the permitted maximum of the sum of the sizes of the input
|
||||
sequence and output sequence.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`c.capacity()`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Returns the maximum sum of the sizes of the input sequence and output
|
||||
sequence that the dynamic buffer can hold without requiring reallocation.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`c.data()`]
|
||||
[`X::const_buffers_type`]
|
||||
[
|
||||
Returns a constant buffer sequence u that represents the memory
|
||||
associated with the input sequence, and where `buffer_size(u) == size()`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.prepare(n)`]
|
||||
[`X:mutable_buffers_type`]
|
||||
[
|
||||
Returns a mutable buffer sequence u representing the output sequence,
|
||||
and where `buffer_size(u) == n`. The dynamic buffer reallocates memory
|
||||
as required. All constant or mutable buffer sequences previously
|
||||
obtained using `data()` or `prepare()` are invalidated.
|
||||
|
||||
Throws: `length_error` if `size() + n` exceeds `max_size()`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.commit(n)`]
|
||||
[ ]
|
||||
[
|
||||
Appends `n` bytes from the start of the output sequence to the end of
|
||||
the input sequence. The remainder of the output sequence is discarded.
|
||||
If `n` is greater than the size of the output sequence, the entire
|
||||
output sequence is appended to the input sequence. All constant or
|
||||
mutable buffer sequences previously obtained using `data()` or
|
||||
`prepare()` are invalidated.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.consume(n)`]
|
||||
[ ]
|
||||
[
|
||||
Removes `n` bytes from beginning of the input sequence. If `n` is
|
||||
greater than the size of the input sequence, the entire input sequence
|
||||
is removed. All constant or mutable buffer sequences previously
|
||||
obtained using `data()` or `prepare()` are invalidated.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
@@ -1,96 +0,0 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 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)
|
||||
]
|
||||
|
||||
[section:Streambuf Streambuf]
|
||||
|
||||
A [*`Streambuf`] represents a logical octet sequence divided in two sections,
|
||||
the input sequence and the output sequence. Octets are written to the output
|
||||
sequence, then moved to the input sequence where they are available for
|
||||
reading. When some or all of the input sequence is no longer needed, it may
|
||||
be consumed.
|
||||
|
||||
The interface to this concept is intended to permit the following
|
||||
implementation strategies:
|
||||
|
||||
* A single contiguous octet array, which is reallocated as necessary to
|
||||
accommodate changes in the size of the octet sequence.
|
||||
|
||||
* A sequence of one or more octet arrays, where each array is of the same
|
||||
size. Additional octet array objects are appended to the sequence to
|
||||
accommodate changes in the size of the octet sequence.
|
||||
|
||||
* A sequence of one or more octet arrays of varying sizes. Additional octet
|
||||
array objects are appended to the sequence to accommodate changes in the
|
||||
size of the character sequence. This is the implementation approached
|
||||
currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
|
||||
|
||||
In the table below:
|
||||
|
||||
* `X` denotes a class meeting the requirements of [*`Streambuf`]
|
||||
* `a` denotes a value of type `X`
|
||||
* `n` denotes a value convertible to `std::size_t`
|
||||
* `U`, `T` denote unspecified types.
|
||||
|
||||
[table Streambuf requirements
|
||||
[[operation] [type] [semantics, pre/post-conditions]]
|
||||
[
|
||||
[`X::const_buffers_type`]
|
||||
[`T`]
|
||||
[`T` meets the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html `ConstBufferSequence`].]
|
||||
]
|
||||
[
|
||||
[`X::mutable_buffers_type`]
|
||||
[`U`]
|
||||
[`U` meets the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html `MutableBufferSequence`].]
|
||||
]
|
||||
[
|
||||
[`a.commit(n)`]
|
||||
[`void`]
|
||||
[Moves bytes from the output sequence to the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.consume(n)`]
|
||||
[`void`]
|
||||
[Removes bytes from the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.data()`]
|
||||
[`T`]
|
||||
[Returns a list of buffers that represents the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.prepare(n)`]
|
||||
[`U`]
|
||||
[Returns a list of buffers that represents the output sequence, with
|
||||
the given size.]
|
||||
]
|
||||
[
|
||||
[`a.size()`]
|
||||
[`std::size_t`]
|
||||
[Returns the size of the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.max_size()`]
|
||||
[`std::size_t`]
|
||||
[Returns the maximum size of the stream buffer.]
|
||||
]
|
||||
[
|
||||
[`read_size_helper(a, n)`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Returns the suggested number of bytes to read into the output
|
||||
sequence where `n` is an upper limit on this value. One possible
|
||||
implementation is to return the number of bytes that may be prepared
|
||||
without causing a dynamic allocation or `n`, whichever is smaller.
|
||||
Calls to `read_size_helper` will be made without namespace
|
||||
qualification, to allow the rules for argument dependent lookup to
|
||||
take effect.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
@@ -358,7 +358,7 @@ handler of the corresponding read function.]
|
||||
|
||||
Because calls to read data may return a variable amount of bytes, the
|
||||
interface to calls that read data require an object that meets the requirements
|
||||
of [link beast.types.Streambuf [*`Streambuf`]]. This concept is modeled on
|
||||
of [link beast.types.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
||||
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
|
||||
|
||||
The implementation does not perform queueing or buffering of messages. If
|
||||
|
||||
@@ -321,12 +321,12 @@ public:
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers,
|
||||
class ReadHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_read(message_v1<isRequest, Body, Headers>& msg,
|
||||
ReadHandler&& handler);
|
||||
|
||||
@@ -416,12 +416,12 @@ public:
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers,
|
||||
class WriteHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_write(message_v1<isRequest, Body, Headers> const& msg,
|
||||
WriteHandler&& handler);
|
||||
|
||||
|
||||
@@ -13,10 +13,78 @@
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
enum error
|
||||
{
|
||||
fail_error = 1
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
class fail_error_category : public boost::system::error_category
|
||||
{
|
||||
public:
|
||||
const char*
|
||||
name() const noexcept override
|
||||
{
|
||||
return "test";
|
||||
}
|
||||
|
||||
std::string
|
||||
message(int ev) const override
|
||||
{
|
||||
switch(static_cast<error>(ev))
|
||||
{
|
||||
default:
|
||||
case error::fail_error:
|
||||
return "test error";
|
||||
}
|
||||
}
|
||||
|
||||
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(error_code const& error, int ev) const noexcept override
|
||||
{
|
||||
return error.value() == ev &&
|
||||
&error.category() == this;
|
||||
}
|
||||
};
|
||||
|
||||
inline
|
||||
boost::system::error_category const&
|
||||
get_error_category()
|
||||
{
|
||||
static fail_error_category const cat{};
|
||||
return cat;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
inline
|
||||
error_code
|
||||
make_error_code(error ev)
|
||||
{
|
||||
return error_code{static_cast<int>(ev),
|
||||
detail::get_error_category()};
|
||||
}
|
||||
|
||||
/** A countdown to simulated failure.
|
||||
|
||||
On the Nth operation, the class will fail with the specified
|
||||
error code, or the default error code of invalid_argument.
|
||||
error code, or the default error code of @ref fail_error.
|
||||
*/
|
||||
class fail_counter
|
||||
{
|
||||
@@ -31,10 +99,10 @@ public:
|
||||
@param The 0-based index of the operation to fail on or after.
|
||||
*/
|
||||
explicit
|
||||
fail_counter(std::size_t n = 0)
|
||||
fail_counter(std::size_t n,
|
||||
error_code ev = make_error_code(fail_error))
|
||||
: n_(n)
|
||||
, ec_(boost::system::errc::make_error_code(
|
||||
boost::system::errc::errc_t::invalid_argument))
|
||||
, ec_(ev)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -66,4 +134,14 @@ public:
|
||||
} // test
|
||||
} // beast
|
||||
|
||||
namespace boost {
|
||||
namespace system {
|
||||
template<>
|
||||
struct is_error_code_enum<beast::test::error>
|
||||
{
|
||||
static bool const value = true;
|
||||
};
|
||||
} // system
|
||||
} // boost
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <beast/core/detail/get_lowest_layer.hpp>
|
||||
#include <beast/websocket/teardown.hpp>
|
||||
#include <beast/test/fail_counter.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace test {
|
||||
@@ -26,8 +27,8 @@ namespace test {
|
||||
template<class NextLayer>
|
||||
class fail_stream
|
||||
{
|
||||
boost::optional<fail_counter> fc_;
|
||||
fail_counter* pfc_;
|
||||
fail_counter fc_;
|
||||
NextLayer next_layer_;
|
||||
|
||||
public:
|
||||
@@ -46,8 +47,8 @@ public:
|
||||
template<class... Args>
|
||||
explicit
|
||||
fail_stream(std::size_t n, Args&&... args)
|
||||
: pfc_(&fc_)
|
||||
, fc_(n)
|
||||
: fc_(n)
|
||||
, pfc_(&*fc_)
|
||||
, next_layer_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
#include <beast/core/static_string.hpp>
|
||||
#include <beast/core/stream_concepts.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/core/streambuf_readstream.hpp>
|
||||
#include <beast/core/dynabuf_readstream.hpp>
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/core/write_streambuf.hpp>
|
||||
#include <beast/core/write_dynabuf.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A @b `Streambuf` that uses multiple buffers internally.
|
||||
/** A @b `DynamicBuffer` that uses multiple buffers internally.
|
||||
|
||||
The implementation uses a sequence of one or more character arrays
|
||||
of varying sizes. Additional character array objects are appended to
|
||||
the sequence to accommodate changes in the size of the character
|
||||
sequence.
|
||||
|
||||
@note Meets the requirements of @b Streambuf.
|
||||
@note Meets the requirements of @b `DynamicBuffer`.
|
||||
|
||||
@tparam Allocator The allocator to use for managing memory.
|
||||
*/
|
||||
@@ -202,26 +202,37 @@ public:
|
||||
basic_streambuf(std::size_t alloc_size = 1024,
|
||||
Allocator const& alloc = allocator_type{});
|
||||
|
||||
/// Get the associated allocator
|
||||
/// Returns a copy of the associated allocator.
|
||||
allocator_type
|
||||
get_allocator() const
|
||||
{
|
||||
return this->member();
|
||||
}
|
||||
|
||||
/// Get the maximum size of the basic_streambuf.
|
||||
/// Returns the size of the input sequence.
|
||||
size_type
|
||||
size() const
|
||||
{
|
||||
return in_size_;
|
||||
}
|
||||
|
||||
/// Returns the permitted maximum sum of the sizes of the input and output sequence.
|
||||
size_type
|
||||
max_size() const
|
||||
{
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
}
|
||||
|
||||
/// Get the size of the input sequence.
|
||||
size_type
|
||||
size() const
|
||||
{
|
||||
return in_size_;
|
||||
}
|
||||
/// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
|
||||
std::size_t
|
||||
capacity() const;
|
||||
|
||||
/** Get a list of buffers that represents the input sequence.
|
||||
|
||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||
*/
|
||||
const_buffers_type
|
||||
data() const;
|
||||
|
||||
/** Get a list of buffers that represents the output sequence, with the given size.
|
||||
|
||||
@@ -239,22 +250,11 @@ public:
|
||||
void
|
||||
commit(size_type n);
|
||||
|
||||
/** Get a list of buffers that represents the input sequence.
|
||||
|
||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||
*/
|
||||
const_buffers_type
|
||||
data() const;
|
||||
|
||||
/// Remove bytes from the input sequence.
|
||||
void
|
||||
consume(size_type n);
|
||||
|
||||
/// Clear everything.
|
||||
void
|
||||
clear();
|
||||
|
||||
// Helper for read_until
|
||||
// Helper for boost::asio::read_until
|
||||
template<class OtherAllocator>
|
||||
friend
|
||||
std::size_t
|
||||
@@ -262,6 +262,9 @@ public:
|
||||
OtherAllocator> const& streambuf, std::size_t max_size);
|
||||
|
||||
private:
|
||||
void
|
||||
clear();
|
||||
|
||||
void
|
||||
move_assign(basic_streambuf& other, std::false_type);
|
||||
|
||||
@@ -277,20 +280,17 @@ private:
|
||||
void
|
||||
delete_list();
|
||||
|
||||
std::size_t
|
||||
prepare_size() const;
|
||||
|
||||
void
|
||||
debug_check() const;
|
||||
};
|
||||
|
||||
/** Format output to a stream buffer.
|
||||
/** Format output to a @ref basic_streambuf.
|
||||
|
||||
@param streambuf The streambuf to write to.
|
||||
@param streambuf The @ref basic_streambuf to write to.
|
||||
|
||||
@param t The object to write.
|
||||
|
||||
@return The stream buffer.
|
||||
@return A reference to the @ref basic_streambuf.
|
||||
*/
|
||||
template<class Allocator, class T>
|
||||
basic_streambuf<Allocator>&
|
||||
|
||||
@@ -35,6 +35,16 @@ struct is_ConstBufferSequence :
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `DynamicBuffer`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_DynamicBuffer : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_DynamicBuffer : detail::is_DynamicBuffer<T>::type
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `MutableBufferSequence`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
@@ -46,16 +56,6 @@ struct is_MutableBufferSequence :
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `Streambuf`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_Streambuf : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_Streambuf : detail::is_Streambuf<T>::type
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_Streambuf
|
||||
class is_DynamicBuffer
|
||||
{
|
||||
template<class U, class R = std::integral_constant<
|
||||
bool, is_BufferSequence<decltype(
|
||||
|
||||
@@ -8,76 +8,96 @@
|
||||
#ifndef BEAST_DETAIL_CI_CHAR_TRAITS_HPP
|
||||
#define BEAST_DETAIL_CI_CHAR_TRAITS_HPP
|
||||
|
||||
#include <boost/range/algorithm/equal.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <cctype>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/** Case-insensitive function object for performing less than comparisons. */
|
||||
inline
|
||||
char
|
||||
tolower(char c)
|
||||
{
|
||||
static std::array<std::uint8_t, 256> constexpr tab = {{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
|
||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
|
||||
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
|
||||
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
|
||||
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
|
||||
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
|
||||
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
|
||||
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
|
||||
}};
|
||||
return static_cast<char>(tab[static_cast<std::uint8_t>(c)]);
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
inline
|
||||
boost::string_ref
|
||||
string_helper(const char (&s)[N])
|
||||
{
|
||||
return boost::string_ref{s, N-1};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
T const&
|
||||
string_helper(T const& t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
// Case-insensitive less
|
||||
struct ci_less
|
||||
{
|
||||
static bool const is_transparent = true;
|
||||
|
||||
template<class S1, class S2>
|
||||
bool
|
||||
operator()(boost::string_ref const& lhs,
|
||||
boost::string_ref const& rhs) const noexcept
|
||||
operator()(S1 const& lhs, S2 const& rhs) const noexcept
|
||||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
auto const s1 = string_helper(lhs);
|
||||
auto const s2 = string_helper(rhs);
|
||||
return std::lexicographical_compare(
|
||||
begin(lhs), end(lhs), begin(rhs), end(rhs),
|
||||
begin(s1), end(s1), begin(s2), end(s2),
|
||||
[](char lhs, char rhs)
|
||||
{
|
||||
return std::tolower(lhs) < std::tolower(rhs);
|
||||
return tolower(lhs) < tolower(rhs);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
inline
|
||||
bool
|
||||
ci_equal(std::pair<const char*, std::size_t> lhs,
|
||||
std::pair<const char*, std::size_t> rhs)
|
||||
// Case-insensitive equal
|
||||
struct ci_equal_pred
|
||||
{
|
||||
if(lhs.second != rhs.second)
|
||||
return false;
|
||||
return std::equal (lhs.first, lhs.first + lhs.second,
|
||||
rhs.first,
|
||||
[] (char lhs, char rhs)
|
||||
bool
|
||||
operator()(char c1, char c2) const noexcept
|
||||
{
|
||||
return std::tolower(lhs) == std::tolower(rhs);
|
||||
return tolower(c1) == tolower(c2);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
inline
|
||||
std::pair<const char*, std::size_t>
|
||||
view(const char (&s)[N])
|
||||
{
|
||||
return {s, N-1};
|
||||
}
|
||||
|
||||
inline
|
||||
std::pair<const char*, std::size_t>
|
||||
view(std::string const& s)
|
||||
{
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
|
||||
/** Returns `true` if strings are case-insensitive equal. */
|
||||
template <class String1, class String2>
|
||||
inline
|
||||
// Case-insensitive equal
|
||||
template<class S1, class S2>
|
||||
bool
|
||||
ci_equal(String1 const& lhs, String2 const& rhs)
|
||||
ci_equal(S1 const& lhs, S2 const& rhs)
|
||||
{
|
||||
return ci_equal(view(lhs), view(rhs));
|
||||
return boost::range::equal(
|
||||
string_helper(lhs), string_helper(rhs),
|
||||
ci_equal_pred{});
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_WRITE_STREAMBUF_HPP
|
||||
#define BEAST_DETAIL_WRITE_STREAMBUF_HPP
|
||||
#ifndef BEAST_DETAIL_WRITE_DYNABUF_HPP
|
||||
#define BEAST_DETAIL_WRITE_DYNABUF_HPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
@@ -42,73 +42,73 @@ public:
|
||||
! is_string_literal<T>::value;
|
||||
};
|
||||
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf,
|
||||
write_dynabuf(DynamicBuffer& dynabuf,
|
||||
boost::asio::const_buffer const& buffer)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(buffer_size(buffer)),
|
||||
dynabuf.commit(buffer_copy(
|
||||
dynabuf.prepare(buffer_size(buffer)),
|
||||
buffer));
|
||||
}
|
||||
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf,
|
||||
write_dynabuf(DynamicBuffer& dynabuf,
|
||||
boost::asio::mutable_buffer const& buffer)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(buffer_size(buffer)),
|
||||
dynabuf.commit(buffer_copy(
|
||||
dynabuf.prepare(buffer_size(buffer)),
|
||||
buffer));
|
||||
}
|
||||
|
||||
template<class Streambuf, class T>
|
||||
template<class DynamicBuffer, class T>
|
||||
typename std::enable_if<
|
||||
is_BufferConvertible<T>::value &&
|
||||
! std::is_convertible<T, boost::asio::const_buffer>::value &&
|
||||
! std::is_convertible<T, boost::asio::mutable_buffer>::value
|
||||
>::type
|
||||
write_streambuf(Streambuf& streambuf, T const& t)
|
||||
write_dynabuf(DynamicBuffer& dynabuf, T const& t)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
auto const buffers = boost::asio::buffer(t);
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(buffer_size(buffers)),
|
||||
dynabuf.commit(buffer_copy(
|
||||
dynabuf.prepare(buffer_size(buffers)),
|
||||
buffers));
|
||||
}
|
||||
|
||||
template<class Streambuf, class Buffers>
|
||||
template<class DynamicBuffer, class Buffers>
|
||||
typename std::enable_if<
|
||||
is_ConstBufferSequence<Buffers>::value &&
|
||||
! is_BufferConvertible<Buffers>::value &&
|
||||
! std::is_convertible<Buffers, boost::asio::const_buffer>::value &&
|
||||
! std::is_convertible<Buffers, boost::asio::mutable_buffer>::value
|
||||
>::type
|
||||
write_streambuf(Streambuf& streambuf, Buffers const& buffers)
|
||||
write_dynabuf(DynamicBuffer& dynabuf, Buffers const& buffers)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(buffer_size(buffers)),
|
||||
dynabuf.commit(buffer_copy(
|
||||
dynabuf.prepare(buffer_size(buffers)),
|
||||
buffers));
|
||||
}
|
||||
|
||||
template<class Streambuf, std::size_t N>
|
||||
template<class DynamicBuffer, std::size_t N>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf, const char (&s)[N])
|
||||
write_dynabuf(DynamicBuffer& dynabuf, const char (&s)[N])
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(N - 1),
|
||||
dynabuf.commit(buffer_copy(
|
||||
dynabuf.prepare(N - 1),
|
||||
boost::asio::buffer(s, N - 1)));
|
||||
}
|
||||
|
||||
template<class Streambuf, class T>
|
||||
template<class DynamicBuffer, class T>
|
||||
typename std::enable_if<
|
||||
! is_string_literal<T>::value &&
|
||||
! is_ConstBufferSequence<T>::value &&
|
||||
@@ -116,22 +116,22 @@ typename std::enable_if<
|
||||
! std::is_convertible<T, boost::asio::const_buffer>::value &&
|
||||
! std::is_convertible<T, boost::asio::mutable_buffer>::value
|
||||
>::type
|
||||
write_streambuf(Streambuf& streambuf, T const& t)
|
||||
write_dynabuf(DynamicBuffer& dynabuf, T const& t)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
auto const s = boost::lexical_cast<std::string>(t);
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(s.size()), buffer(s)));
|
||||
dynabuf.commit(buffer_copy(
|
||||
dynabuf.prepare(s.size()), buffer(s)));
|
||||
}
|
||||
|
||||
template<class Streambuf, class T0, class T1, class... TN>
|
||||
template<class DynamicBuffer, class T0, class T1, class... TN>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf,
|
||||
write_dynabuf(DynamicBuffer& dynabuf,
|
||||
T0 const& t0, T1 const& t1, TN const&... tn)
|
||||
{
|
||||
write_streambuf(streambuf, t0);
|
||||
write_streambuf(streambuf, t1, tn...);
|
||||
write_dynabuf(dynabuf, t0);
|
||||
write_dynabuf(dynabuf, t1, tn...);
|
||||
}
|
||||
|
||||
} // detail
|
||||
@@ -5,8 +5,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_STREAMBUF_READSTREAM_HPP
|
||||
#define BEAST_STREAMBUF_READSTREAM_HPP
|
||||
#ifndef BEAST_DYNABUF_READSTREAM_HPP
|
||||
#define BEAST_DYNABUF_READSTREAM_HPP
|
||||
|
||||
#include <beast/core/async_completion.hpp>
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
@@ -22,11 +22,11 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A @b `Stream` with attached @b `Streambuf` to buffer reads.
|
||||
/** A @b `Stream` with attached @b `DynamicBuffer` to buffer reads.
|
||||
|
||||
This wraps a @b `Stream` implementation so that calls to write are
|
||||
passed through to the underlying stream, while calls to read will
|
||||
first consume the input sequence stored in a @b `Streambuf` which
|
||||
first consume the input sequence stored in a @b `DynamicBuffer` which
|
||||
is part of the object.
|
||||
|
||||
The use-case for this class is different than that of the
|
||||
@@ -50,9 +50,9 @@ namespace beast {
|
||||
// Process the next HTTP headers on the stream,
|
||||
// leaving excess bytes behind for the next call.
|
||||
//
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void process_http_message(
|
||||
streambuf_readstream<Streambuf>& stream)
|
||||
dynabuf_readstream<DynamicBuffer>& stream)
|
||||
{
|
||||
// Read up to and including the end of the HTTP
|
||||
// headers, leaving the sequence in the stream's
|
||||
@@ -85,26 +85,24 @@ namespace beast {
|
||||
|
||||
@tparam Stream The type of stream to wrap.
|
||||
|
||||
@tparam Streambuf The type of stream buffer to use.
|
||||
@tparam DynamicBuffer The type of stream buffer to use.
|
||||
*/
|
||||
template<class Stream, class Streambuf>
|
||||
class streambuf_readstream
|
||||
template<class Stream, class DynamicBuffer>
|
||||
class dynabuf_readstream
|
||||
{
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
|
||||
using error_code = boost::system::error_code;
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
|
||||
template<class Buffers, class Handler>
|
||||
class read_some_op;
|
||||
|
||||
Streambuf sb_;
|
||||
DynamicBuffer sb_;
|
||||
std::size_t capacity_ = 0;
|
||||
Stream next_layer_;
|
||||
|
||||
public:
|
||||
/// The type of the internal buffer
|
||||
using streambuf_type = Streambuf;
|
||||
using dynabuf_type = DynamicBuffer;
|
||||
|
||||
/// The type of the next layer.
|
||||
using next_layer_type =
|
||||
@@ -124,14 +122,14 @@ public:
|
||||
@note The behavior of move assignment on or from streams
|
||||
with active or pending operations is undefined.
|
||||
*/
|
||||
streambuf_readstream(streambuf_readstream&&) = default;
|
||||
dynabuf_readstream(dynabuf_readstream&&) = default;
|
||||
|
||||
/** Move assignment.
|
||||
|
||||
@note The behavior of move assignment on or from streams
|
||||
with active or pending operations is undefined.
|
||||
*/
|
||||
streambuf_readstream& operator=(streambuf_readstream&&) = default;
|
||||
dynabuf_readstream& operator=(dynabuf_readstream&&) = default;
|
||||
|
||||
/** Construct the wrapping stream.
|
||||
|
||||
@@ -139,7 +137,7 @@ public:
|
||||
*/
|
||||
template<class... Args>
|
||||
explicit
|
||||
streambuf_readstream(Args&&... args);
|
||||
dynabuf_readstream(Args&&... args);
|
||||
|
||||
/// Get a reference to the next layer.
|
||||
next_layer_type&
|
||||
@@ -176,7 +174,7 @@ public:
|
||||
by causing the internal buffer size to increase beyond
|
||||
the caller defined maximum.
|
||||
*/
|
||||
Streambuf&
|
||||
DynamicBuffer&
|
||||
buffer()
|
||||
{
|
||||
return sb_;
|
||||
@@ -189,7 +187,7 @@ public:
|
||||
by causing the internal buffer size to increase beyond
|
||||
the caller defined maximum.
|
||||
*/
|
||||
Streambuf const&
|
||||
DynamicBuffer const&
|
||||
buffer() const
|
||||
{
|
||||
return sb_;
|
||||
@@ -277,6 +275,6 @@ public:
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/streambuf_readstream.ipp>
|
||||
#include <beast/core/impl/dynabuf_readstream.ipp>
|
||||
|
||||
#endif
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP
|
||||
#define BEAST_IMPL_BASIC_STREAMBUF_IPP
|
||||
|
||||
#include <beast/core/detail/write_streambuf.hpp>
|
||||
#include <beast/core/detail/write_dynabuf.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
@@ -527,6 +527,28 @@ basic_streambuf<Allocator>::basic_streambuf(
|
||||
"basic_streambuf: invalid alloc_size");
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
std::size_t
|
||||
basic_streambuf<Allocator>::capacity() const
|
||||
{
|
||||
auto pos = out_;
|
||||
if(pos == list_.end())
|
||||
return 0;
|
||||
auto n = pos->size() - out_pos_;
|
||||
while(++pos != list_.end())
|
||||
n += pos->size();
|
||||
return in_size_ + n;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_streambuf<Allocator>::
|
||||
data() const ->
|
||||
const_buffers_type
|
||||
{
|
||||
return const_buffers_type(*this);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_streambuf<Allocator>::prepare(size_type n) ->
|
||||
@@ -646,14 +668,6 @@ basic_streambuf<Allocator>::commit(size_type n)
|
||||
debug_check();
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_streambuf<Allocator>::data() const ->
|
||||
const_buffers_type
|
||||
{
|
||||
return const_buffers_type(*this);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_streambuf<Allocator>::consume(size_type n)
|
||||
@@ -717,7 +731,8 @@ basic_streambuf<Allocator>::consume(size_type n)
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_streambuf<Allocator>::clear()
|
||||
basic_streambuf<Allocator>::
|
||||
clear()
|
||||
{
|
||||
delete_list();
|
||||
list_.clear();
|
||||
@@ -795,21 +810,6 @@ basic_streambuf<Allocator>::delete_list()
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of bytes which can be
|
||||
// prepared without causing a memory allocation.
|
||||
template<class Allocator>
|
||||
std::size_t
|
||||
basic_streambuf<Allocator>::prepare_size() const
|
||||
{
|
||||
auto pos = out_;
|
||||
if(pos == list_.end())
|
||||
return 0;
|
||||
auto n = pos->size() - out_pos_;
|
||||
while(++pos != list_.end())
|
||||
n += pos->size();
|
||||
return n;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_streambuf<Allocator>::debug_check() const
|
||||
@@ -855,7 +855,7 @@ std::size_t
|
||||
read_size_helper(basic_streambuf<
|
||||
Allocator> const& streambuf, std::size_t max_size)
|
||||
{
|
||||
auto const avail = streambuf.prepare_size();
|
||||
auto const avail = streambuf.capacity() - streambuf.size();
|
||||
if(avail == 0)
|
||||
return std::min(max_size,
|
||||
std::max<std::size_t>(512, streambuf.alloc_size_));
|
||||
@@ -866,7 +866,7 @@ template<class Alloc, class T>
|
||||
basic_streambuf<Alloc>&
|
||||
operator<<(basic_streambuf<Alloc>& streambuf, T const& t)
|
||||
{
|
||||
detail::write_streambuf(streambuf, t);
|
||||
detail::write_dynabuf(streambuf, t);
|
||||
return streambuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_STREAMBUF_READSTREAM_IPP
|
||||
#define BEAST_IMPL_STREAMBUF_READSTREAM_IPP
|
||||
#ifndef BEAST_IMPL_DYNABUF_READSTREAM_HPP
|
||||
#define BEAST_IMPL_DYNABUF_READSTREAM_HPP
|
||||
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
#include <beast/core/handler_concepts.hpp>
|
||||
@@ -16,24 +16,24 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
template<class Stream, class DynamicBuffer>
|
||||
template<class MutableBufferSequence, class Handler>
|
||||
class streambuf_readstream<
|
||||
Stream, Streambuf>::read_some_op
|
||||
class dynabuf_readstream<
|
||||
Stream, DynamicBuffer>::read_some_op
|
||||
{
|
||||
using alloc_type =
|
||||
handler_alloc<char, Handler>;
|
||||
|
||||
struct data
|
||||
{
|
||||
streambuf_readstream& srs;
|
||||
dynabuf_readstream& srs;
|
||||
MutableBufferSequence bs;
|
||||
Handler h;
|
||||
int state = 0;
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_,
|
||||
streambuf_readstream& srs_,
|
||||
dynabuf_readstream& srs_,
|
||||
MutableBufferSequence const& bs_)
|
||||
: srs(srs_)
|
||||
, bs(bs_)
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
|
||||
template<class DeducedHandler, class... Args>
|
||||
read_some_op(DeducedHandler&& h,
|
||||
streambuf_readstream& srs, Args&&... args)
|
||||
dynabuf_readstream& srs, Args&&... args)
|
||||
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||
std::forward<DeducedHandler>(h), srs,
|
||||
std::forward<Args>(args)...))
|
||||
@@ -94,10 +94,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
template<class Stream, class DynamicBuffer>
|
||||
template<class MutableBufferSequence, class Handler>
|
||||
void
|
||||
streambuf_readstream<Stream, Streambuf>::
|
||||
dynabuf_readstream<Stream, DynamicBuffer>::
|
||||
read_some_op<MutableBufferSequence, Handler>::operator()(
|
||||
error_code const& ec, std::size_t bytes_transferred)
|
||||
{
|
||||
@@ -155,18 +155,18 @@ read_some_op<MutableBufferSequence, Handler>::operator()(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
template<class Stream, class DynamicBuffer>
|
||||
template<class... Args>
|
||||
streambuf_readstream<Stream, Streambuf>::
|
||||
streambuf_readstream(Args&&... args)
|
||||
dynabuf_readstream<Stream, DynamicBuffer>::
|
||||
dynabuf_readstream(Args&&... args)
|
||||
: next_layer_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
template<class Stream, class DynamicBuffer>
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
auto
|
||||
streambuf_readstream<Stream, Streambuf>::
|
||||
dynabuf_readstream<Stream, DynamicBuffer>::
|
||||
async_write_some(ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler) ->
|
||||
typename async_completion<
|
||||
@@ -184,10 +184,10 @@ async_write_some(ConstBufferSequence const& buffers,
|
||||
std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
template<class Stream, class DynamicBuffer>
|
||||
template<class MutableBufferSequence>
|
||||
std::size_t
|
||||
streambuf_readstream<Stream, Streambuf>::
|
||||
dynabuf_readstream<Stream, DynamicBuffer>::
|
||||
read_some(
|
||||
MutableBufferSequence const& buffers)
|
||||
{
|
||||
@@ -203,10 +203,10 @@ read_some(
|
||||
return n;
|
||||
}
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
template<class Stream, class DynamicBuffer>
|
||||
template<class MutableBufferSequence>
|
||||
std::size_t
|
||||
streambuf_readstream<Stream, Streambuf>::
|
||||
dynabuf_readstream<Stream, DynamicBuffer>::
|
||||
read_some(MutableBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
{
|
||||
@@ -232,10 +232,10 @@ read_some(MutableBufferSequence const& buffers,
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
template<class Stream, class DynamicBuffer>
|
||||
template<class MutableBufferSequence, class ReadHandler>
|
||||
auto
|
||||
streambuf_readstream<Stream, Streambuf>::
|
||||
dynabuf_readstream<Stream, DynamicBuffer>::
|
||||
async_read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler) ->
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A @b `Streambuf` with a fixed size internal buffer.
|
||||
/** A @b `DynamicBuffer` with a fixed size internal buffer.
|
||||
|
||||
Ownership of the underlying storage belongs to the derived class.
|
||||
|
||||
|
||||
@@ -506,8 +506,6 @@ compare(
|
||||
|
||||
} // detail
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator==(
|
||||
@@ -672,8 +670,6 @@ operator>=(
|
||||
return detail::compare(lhs, s) >= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,15 +25,16 @@ namespace beast {
|
||||
@return A string representing the contents of the input area.
|
||||
|
||||
@note This function participates in overload resolution only if
|
||||
the streambuf parameter meets the requirements of @b `Streambuf`.
|
||||
the buffers parameter meets the requirements of @b `ConstBufferSequence`.
|
||||
*/
|
||||
template<class ConstBufferSequence
|
||||
#if ! GENERATING_DOCS
|
||||
,class = std::enable_if<is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value>
|
||||
#endif
|
||||
>
|
||||
template<class ConstBufferSequence>
|
||||
#if GENERATING_DOCS
|
||||
std::string
|
||||
#else
|
||||
typename std::enable_if<
|
||||
is_ConstBufferSequence<ConstBufferSequence>::value,
|
||||
std::string>::type
|
||||
#endif
|
||||
to_string(ConstBufferSequence const& buffers)
|
||||
{
|
||||
using boost::asio::buffer_cast;
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_WRITE_STREAMBUF_HPP
|
||||
#define BEAST_WRITE_STREAMBUF_HPP
|
||||
#ifndef BEAST_WRITE_DYNABUF_HPP
|
||||
#define BEAST_WRITE_DYNABUF_HPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <beast/core/detail/write_streambuf.hpp>
|
||||
#include <beast/core/detail/write_dynabuf.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Write to a Streambuf.
|
||||
/** Write to a @b `DynamicBuffer`.
|
||||
|
||||
This function appends the serialized representation of each provided
|
||||
argument into the stream buffer. It is capable of converting the
|
||||
argument into the dynamic buffer. It is capable of converting the
|
||||
following types of arguments:
|
||||
|
||||
@li `boost::asio::const_buffer`
|
||||
@@ -33,29 +33,29 @@ namespace beast {
|
||||
|
||||
For all types not listed above, the function will invoke
|
||||
`boost::lexical_cast` on the argument in an attempt to convert to
|
||||
a string, which is then appended to the stream buffer.
|
||||
a string, which is then appended to the dynamic buffer.
|
||||
|
||||
When this function serializes numbers, it converts them to
|
||||
their text representation as if by a call to `std::to_string`.
|
||||
|
||||
@param streambuf The stream buffer to write to.
|
||||
@param dynabuf The dynamic buffer to write to.
|
||||
|
||||
@param args A list of one or more arguments to write.
|
||||
|
||||
@throws unspecified Any exceptions thrown by `boost::lexical_cast`.
|
||||
|
||||
@note This function participates in overload resolution only if
|
||||
the `streambuf` parameter meets the requirements of @b `Streambuf`.
|
||||
the `dynabuf` parameter meets the requirements of @b `DynamicBuffer`.
|
||||
*/
|
||||
template<class Streambuf, class... Args>
|
||||
template<class DynamicBuffer, class... Args>
|
||||
#if GENERATING_DOCS
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<is_Streambuf<Streambuf>::value>::type
|
||||
typename std::enable_if<is_DynamicBuffer<DynamicBuffer>::value>::type
|
||||
#endif
|
||||
write(Streambuf& streambuf, Args const&... args)
|
||||
write(DynamicBuffer& dynabuf, Args const&... args)
|
||||
{
|
||||
detail::write_streambuf(streambuf, args...);
|
||||
detail::write_dynabuf(dynabuf, args...);
|
||||
}
|
||||
|
||||
} // beast
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/reason.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/http/streambuf_body.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/http/write.hpp>
|
||||
|
||||
95
src/beast/include/beast/http/basic_dynabuf_body.hpp
Normal file
95
src/beast/include/beast/http/basic_dynabuf_body.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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_BASIC_DYNABUF_BODY_HPP
|
||||
#define BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
|
||||
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** A message body represented by a @b `DynamicBuffer`
|
||||
|
||||
Meets the requirements of @b `Body`.
|
||||
*/
|
||||
template<class DynamicBuffer>
|
||||
struct basic_dynabuf_body
|
||||
{
|
||||
/// The type of the `message::body` member
|
||||
using value_type = DynamicBuffer;
|
||||
|
||||
#if GENERATING_DOCS
|
||||
private:
|
||||
#endif
|
||||
|
||||
class reader
|
||||
{
|
||||
value_type& sb_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
reader(message<isRequest,
|
||||
basic_dynabuf_body, Headers>& m) noexcept
|
||||
: sb_(m.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
write(void const* data,
|
||||
std::size_t size, error_code&) noexcept
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
sb_.commit(buffer_copy(
|
||||
sb_.prepare(size), buffer(data, size)));
|
||||
}
|
||||
};
|
||||
|
||||
class writer
|
||||
{
|
||||
DynamicBuffer const& body_;
|
||||
|
||||
public:
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
writer(message<
|
||||
isRequest, basic_dynabuf_body, Headers> const& m)
|
||||
: body_(m.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
{
|
||||
return body_.size();
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
{
|
||||
write(body_.data());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -246,8 +246,7 @@ public:
|
||||
Field names are stored as-is, but comparison are case-insensitive.
|
||||
The container preserves the order of insertion of fields with
|
||||
different names. For fields with the same name, the implementation
|
||||
concatenates values inserted with duplicate names as per the
|
||||
rules in rfc2616 section 4.2.
|
||||
concatenates values inserted with duplicate names as per rfc7230.
|
||||
|
||||
@note Meets the requirements of @b `FieldSequence`.
|
||||
*/
|
||||
@@ -393,18 +392,16 @@ public:
|
||||
*/
|
||||
// VFALCO TODO Consider allowing rvalue references for std::move?
|
||||
void
|
||||
insert(boost::string_ref const& name,
|
||||
boost::string_ref const& value);
|
||||
insert(boost::string_ref const& name, boost::string_ref value);
|
||||
|
||||
/** Insert a field value.
|
||||
|
||||
If a field value already exists the new value will be
|
||||
extended as per RFC2616 Section 4.2.
|
||||
*/
|
||||
template<class T,
|
||||
class = typename std::enable_if<
|
||||
! std::is_constructible<boost::string_ref, T>::value>::type>
|
||||
void
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
! std::is_constructible<boost::string_ref, T>::value>::type
|
||||
insert(boost::string_ref name, T const& value)
|
||||
{
|
||||
insert(name,
|
||||
@@ -414,21 +411,19 @@ public:
|
||||
/** Replace a field value.
|
||||
|
||||
The current field value, if any, is removed. Then the
|
||||
specified value is inserted as if by insert(field, value).
|
||||
specified value is inserted as if by `insert(field, value)`.
|
||||
*/
|
||||
void
|
||||
replace(boost::string_ref const& name,
|
||||
boost::string_ref const& value);
|
||||
replace(boost::string_ref const& name, boost::string_ref value);
|
||||
|
||||
/** Replace a field value.
|
||||
|
||||
The current field value, if any, is removed. Then the
|
||||
specified value is inserted as if by insert(field, value).
|
||||
specified value is inserted as if by `insert(field, value)`.
|
||||
*/
|
||||
template<class T,
|
||||
class = typename std::enable_if<
|
||||
! std::is_constructible<boost::string_ref, T>::value>::type>
|
||||
void
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
! std::is_constructible<boost::string_ref, T>::value>::type
|
||||
replace(boost::string_ref const& name, T const& value)
|
||||
{
|
||||
replace(name,
|
||||
|
||||
@@ -25,17 +25,65 @@ namespace http {
|
||||
namespace parse_flag {
|
||||
enum values
|
||||
{
|
||||
chunked = 1 << 0,
|
||||
connection_keep_alive = 1 << 1,
|
||||
connection_close = 1 << 2,
|
||||
connection_upgrade = 1 << 3,
|
||||
trailing = 1 << 4,
|
||||
upgrade = 1 << 5,
|
||||
skipbody = 1 << 6,
|
||||
contentlength = 1 << 7
|
||||
chunked = 1,
|
||||
connection_keep_alive = 2,
|
||||
connection_close = 4,
|
||||
connection_upgrade = 8,
|
||||
trailing = 16,
|
||||
upgrade = 32,
|
||||
skipbody = 64,
|
||||
contentlength = 128
|
||||
};
|
||||
} // parse_flag
|
||||
|
||||
/** Headers maximum size option.
|
||||
|
||||
Sets the maximum number of cumulative bytes allowed
|
||||
including all header octets. A value of zero indicates
|
||||
no limit on the number of header octets
|
||||
|
||||
The default headers maximum size is 16KB (16,384 bytes).
|
||||
|
||||
@note Objects of this type are passed to @ref set_option.
|
||||
*/
|
||||
struct headers_max_size
|
||||
{
|
||||
std::size_t value;
|
||||
|
||||
explicit
|
||||
headers_max_size(std::size_t v)
|
||||
: value(v)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Body maximum size option.
|
||||
|
||||
Sets the maximum number of cumulative bytes allowed including
|
||||
all body octets. Octets in chunk-encoded bodies are counted
|
||||
after decoding. A value of zero indicates no limit on
|
||||
the number of body octets.
|
||||
|
||||
The default body maximum size for requests is 4MB (four
|
||||
megabytes or 4,194,304 bytes) and unlimited for responses.
|
||||
|
||||
@note Objects of this type are passed to @ref set_option.
|
||||
*/
|
||||
struct body_max_size
|
||||
{
|
||||
std::size_t value;
|
||||
|
||||
explicit
|
||||
body_max_size(std::size_t v)
|
||||
: value(v)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// The value returned when no content length is known or applicable.
|
||||
static std::uint64_t constexpr no_content_length =
|
||||
std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
/** A parser for decoding HTTP/1 wire format messages.
|
||||
|
||||
This parser is designed to efficiently parse messages in the
|
||||
@@ -85,7 +133,7 @@ enum values
|
||||
|
||||
Called for each piece of the current header value.
|
||||
|
||||
@li `int on_headers(error_code&)`
|
||||
@li `int on_headers(std::uint64_t content_length, error_code&)`
|
||||
|
||||
Called when all the headers have been parsed successfully.
|
||||
|
||||
@@ -126,90 +174,12 @@ enum values
|
||||
presented with request or response message.
|
||||
*/
|
||||
template<bool isRequest, class Derived>
|
||||
class basic_parser_v1
|
||||
class basic_parser_v1 : public detail::parser_base
|
||||
{
|
||||
private:
|
||||
using self = basic_parser_v1;
|
||||
typedef void(self::*pmf_t)(error_code&, boost::string_ref const&);
|
||||
|
||||
static std::uint64_t constexpr no_content_length =
|
||||
std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
enum state : std::uint8_t
|
||||
{
|
||||
s_closed = 1,
|
||||
|
||||
s_req_start,
|
||||
s_req_method_start,
|
||||
s_req_method,
|
||||
s_req_space_before_url,
|
||||
s_req_url_start,
|
||||
s_req_url,
|
||||
s_req_http_start,
|
||||
s_req_http_H,
|
||||
s_req_http_HT,
|
||||
s_req_http_HTT,
|
||||
s_req_http_HTTP,
|
||||
s_req_major_start,
|
||||
s_req_major,
|
||||
s_req_minor_start,
|
||||
s_req_minor,
|
||||
s_req_line_end,
|
||||
|
||||
s_res_start,
|
||||
s_res_H,
|
||||
s_res_HT,
|
||||
s_res_HTT,
|
||||
s_res_HTTP,
|
||||
s_res_major_start,
|
||||
s_res_major,
|
||||
s_res_minor_start,
|
||||
s_res_minor,
|
||||
s_res_status_code_start,
|
||||
s_res_status_code,
|
||||
s_res_status_start,
|
||||
s_res_status,
|
||||
s_res_line_almost_done,
|
||||
s_res_line_done,
|
||||
|
||||
s_header_field_start,
|
||||
s_header_field,
|
||||
s_header_value_start,
|
||||
s_header_value_discard_lWs0,
|
||||
s_header_value_discard_ws0,
|
||||
s_header_value_almost_done0,
|
||||
s_header_value_text_start,
|
||||
s_header_value_discard_lWs,
|
||||
s_header_value_discard_ws,
|
||||
s_header_value_text,
|
||||
s_header_value_almost_done,
|
||||
|
||||
s_headers_almost_done,
|
||||
s_headers_done,
|
||||
|
||||
s_chunk_size_start,
|
||||
s_chunk_size,
|
||||
s_chunk_parameters,
|
||||
s_chunk_size_almost_done,
|
||||
|
||||
// states below do not count towards
|
||||
// the limit on the size of the message
|
||||
|
||||
s_body_identity0,
|
||||
s_body_identity,
|
||||
s_body_identity_eof0,
|
||||
s_body_identity_eof,
|
||||
|
||||
s_chunk_data_start,
|
||||
s_chunk_data,
|
||||
s_chunk_data_almost_done,
|
||||
s_chunk_data_done,
|
||||
|
||||
s_complete,
|
||||
s_restart,
|
||||
s_closed_complete
|
||||
};
|
||||
|
||||
enum field_state : std::uint8_t
|
||||
{
|
||||
h_general = 0,
|
||||
@@ -224,25 +194,36 @@ private:
|
||||
h_matching_upgrade,
|
||||
|
||||
h_connection,
|
||||
h_content_length0,
|
||||
h_content_length,
|
||||
h_content_length_ows,
|
||||
h_transfer_encoding,
|
||||
h_upgrade,
|
||||
|
||||
h_matching_transfer_encoding_chunked,
|
||||
h_matching_connection_token_start,
|
||||
h_matching_transfer_encoding_general,
|
||||
h_matching_connection_keep_alive,
|
||||
h_matching_connection_close,
|
||||
h_matching_connection_upgrade,
|
||||
h_matching_connection_token,
|
||||
|
||||
h_transfer_encoding_chunked,
|
||||
h_transfer_encoding_chunked_ows,
|
||||
|
||||
h_connection_keep_alive,
|
||||
h_connection_keep_alive_ows,
|
||||
h_connection_close,
|
||||
h_connection_close_ows,
|
||||
h_connection_upgrade,
|
||||
h_connection_upgrade_ows,
|
||||
h_connection_token,
|
||||
h_connection_token_ows
|
||||
};
|
||||
|
||||
std::size_t h_max_;
|
||||
std::size_t h_left_;
|
||||
std::size_t b_max_;
|
||||
std::size_t b_left_;
|
||||
std::uint64_t content_length_;
|
||||
std::uint64_t nread_;
|
||||
pmf_t cb_;
|
||||
state s_ : 8;
|
||||
unsigned flags_ : 8;
|
||||
@@ -260,10 +241,42 @@ public:
|
||||
/// Copy assignment.
|
||||
basic_parser_v1& operator=(basic_parser_v1 const&) = default;
|
||||
|
||||
/// Constructor
|
||||
basic_parser_v1()
|
||||
/// Default constructor
|
||||
basic_parser_v1();
|
||||
|
||||
/** Set options on the parser.
|
||||
|
||||
@param args One or more parser options to set.
|
||||
*/
|
||||
#if GENERATING_DOCS
|
||||
template<class... Args>
|
||||
void
|
||||
set_option(Args&&... args)
|
||||
#else
|
||||
template<class A1, class A2, class... An>
|
||||
void
|
||||
set_option(A1&& a1, A2&& a2, An&&... an)
|
||||
#endif
|
||||
{
|
||||
init(std::integral_constant<bool, isRequest>{});
|
||||
set_option(std::forward<A1>(a1));
|
||||
set_option(std::forward<A2>(a2),
|
||||
std::forward<An>(an)...);
|
||||
}
|
||||
|
||||
/// Set the headers maximum size option
|
||||
void
|
||||
set_option(headers_max_size const& o)
|
||||
{
|
||||
h_max_ = o.value;
|
||||
h_left_ = h_max_;
|
||||
}
|
||||
|
||||
/// Set the body maximum size option
|
||||
void
|
||||
set_option(body_max_size const& o)
|
||||
{
|
||||
b_max_ = o.value;
|
||||
b_left_ = b_max_;
|
||||
}
|
||||
|
||||
/// Returns internal flags associated with the parser.
|
||||
@@ -373,14 +386,14 @@ public:
|
||||
@return The number of bytes consumed in the input sequence.
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
std::size_t
|
||||
#else
|
||||
#else
|
||||
typename std::enable_if<
|
||||
! std::is_convertible<ConstBufferSequence,
|
||||
boost::asio::const_buffer>::value,
|
||||
std::size_t>::type
|
||||
#endif
|
||||
#endif
|
||||
write(ConstBufferSequence const& buffers, error_code& ec);
|
||||
|
||||
/** Write a single buffer of data to the parser.
|
||||
@@ -413,17 +426,48 @@ private:
|
||||
}
|
||||
|
||||
void
|
||||
init(std::true_type)
|
||||
reset(std::true_type)
|
||||
{
|
||||
s_ = s_req_start;
|
||||
}
|
||||
|
||||
void
|
||||
init(std::false_type)
|
||||
reset(std::false_type)
|
||||
{
|
||||
s_ = s_res_start;
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
h_left_ = h_max_;
|
||||
b_left_ = b_max_;
|
||||
reset(std::integral_constant<bool, isRequest>{});
|
||||
}
|
||||
|
||||
void
|
||||
init(std::true_type)
|
||||
{
|
||||
// 16KB max headers, 4MB max body
|
||||
h_max_ = 16 * 1024;
|
||||
b_max_ = 4 * 1024 * 1024;
|
||||
}
|
||||
|
||||
void
|
||||
init(std::false_type)
|
||||
{
|
||||
// 16KB max headers, unlimited body
|
||||
h_max_ = 16 * 1024;
|
||||
b_max_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
init()
|
||||
{
|
||||
init(std::integral_constant<bool, isRequest>{});
|
||||
reset();
|
||||
}
|
||||
|
||||
bool
|
||||
needs_eof(std::true_type) const;
|
||||
|
||||
@@ -584,7 +628,7 @@ private:
|
||||
{
|
||||
template<class T, class R = std::is_same<int,
|
||||
decltype(std::declval<T>().on_headers(
|
||||
std::declval<error_code&>()))>>
|
||||
std::declval<std::uint64_t>(), std::declval<error_code&>()))>>
|
||||
static R check(int);
|
||||
template <class>
|
||||
static std::false_type check(...);
|
||||
@@ -661,9 +705,17 @@ private:
|
||||
void call_on_method(error_code& ec,
|
||||
boost::string_ref const& s)
|
||||
{
|
||||
if(! h_max_ || s.size() <= h_left_)
|
||||
{
|
||||
h_left_ -= s.size();
|
||||
call_on_method(ec, s, std::integral_constant<bool,
|
||||
isRequest && has_on_method<Derived>::value>{});
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = parse_error::headers_too_big;
|
||||
}
|
||||
}
|
||||
|
||||
void call_on_uri(error_code& ec,
|
||||
boost::string_ref const& s, std::true_type)
|
||||
@@ -678,9 +730,17 @@ private:
|
||||
|
||||
void call_on_uri(error_code& ec, boost::string_ref const& s)
|
||||
{
|
||||
if(! h_max_ || s.size() <= h_left_)
|
||||
{
|
||||
h_left_ -= s.size();
|
||||
call_on_uri(ec, s, std::integral_constant<bool,
|
||||
isRequest && has_on_uri<Derived>::value>{});
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = parse_error::headers_too_big;
|
||||
}
|
||||
}
|
||||
|
||||
void call_on_reason(error_code& ec,
|
||||
boost::string_ref const& s, std::true_type)
|
||||
@@ -695,9 +755,17 @@ private:
|
||||
|
||||
void call_on_reason(error_code& ec, boost::string_ref const& s)
|
||||
{
|
||||
if(! h_max_ || s.size() <= h_left_)
|
||||
{
|
||||
h_left_ -= s.size();
|
||||
call_on_reason(ec, s, std::integral_constant<bool,
|
||||
! isRequest && has_on_reason<Derived>::value>{});
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = parse_error::headers_too_big;
|
||||
}
|
||||
}
|
||||
|
||||
void call_on_request(error_code& ec, std::true_type)
|
||||
{
|
||||
@@ -742,8 +810,16 @@ private:
|
||||
|
||||
void call_on_field(error_code& ec, boost::string_ref const& s)
|
||||
{
|
||||
if(! h_max_ || s.size() <= h_left_)
|
||||
{
|
||||
h_left_ -= s.size();
|
||||
call_on_field(ec, s, has_on_field<Derived>{});
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = parse_error::headers_too_big;
|
||||
}
|
||||
}
|
||||
|
||||
void call_on_value(error_code& ec,
|
||||
boost::string_ref const& s, std::true_type)
|
||||
@@ -758,22 +834,32 @@ private:
|
||||
|
||||
void call_on_value(error_code& ec, boost::string_ref const& s)
|
||||
{
|
||||
if(! h_max_ || s.size() <= h_left_)
|
||||
{
|
||||
h_left_ -= s.size();
|
||||
call_on_value(ec, s, has_on_value<Derived>{});
|
||||
}
|
||||
|
||||
int call_on_headers(error_code& ec, std::true_type)
|
||||
else
|
||||
{
|
||||
return impl().on_headers(ec);
|
||||
ec = parse_error::headers_too_big;
|
||||
}
|
||||
}
|
||||
|
||||
int call_on_headers(error_code& ec, std::false_type)
|
||||
int call_on_headers(error_code& ec,
|
||||
std::uint64_t content_length, std::true_type)
|
||||
{
|
||||
return impl().on_headers(content_length, ec);
|
||||
}
|
||||
|
||||
int call_on_headers(error_code& ec, std::uint64_t, std::false_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int call_on_headers(error_code& ec)
|
||||
{
|
||||
return call_on_headers(ec, has_on_headers<Derived>{});
|
||||
return call_on_headers(ec, content_length_,
|
||||
has_on_headers<Derived>{});
|
||||
}
|
||||
|
||||
void call_on_body(error_code& ec,
|
||||
@@ -789,8 +875,16 @@ private:
|
||||
|
||||
void call_on_body(error_code& ec, boost::string_ref const& s)
|
||||
{
|
||||
if(! b_max_ || s.size() <= b_left_)
|
||||
{
|
||||
b_left_ -= s.size();
|
||||
call_on_body(ec, s, has_on_body<Derived>{});
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = parse_error::body_too_big;
|
||||
}
|
||||
}
|
||||
|
||||
void call_on_complete(error_code& ec, std::true_type)
|
||||
{
|
||||
|
||||
@@ -17,137 +17,6 @@ namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
// '0'...'9'
|
||||
inline
|
||||
bool
|
||||
is_digit(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_token(char c)
|
||||
{
|
||||
/* token = 1*<any CHAR except CTLs or separators>
|
||||
CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
sep = "(" | ")" | "<" | ">" | "@"
|
||||
| "," | ";" | ":" | "\" | <">
|
||||
| "/" | "[" | "]" | "?" | "="
|
||||
| "{" | "}" | SP | HT
|
||||
*/
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)] != 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_text(char c)
|
||||
{
|
||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)] != 0;
|
||||
}
|
||||
|
||||
// converts to lower case,
|
||||
// returns 0 if not a valid token char
|
||||
//
|
||||
inline
|
||||
char
|
||||
to_field_char(char c)
|
||||
{
|
||||
/* token = 1*<any CHAR except CTLs or separators>
|
||||
CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
sep = "(" | ")" | "<" | ">" | "@"
|
||||
| "," | ";" | ":" | "\" | <">
|
||||
| "/" | "[" | "]" | "?" | "="
|
||||
| "{" | "}" | SP | HT
|
||||
*/
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, '!', 0, '#', '$', '%', '&', '\'', 0, 0, '*', '+', 0, '-', '.', 0,
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
|
||||
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, '^', '_',
|
||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, '|', 0, '~', 0
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
// converts to lower case,
|
||||
// returns 0 if not a valid text char
|
||||
//
|
||||
inline
|
||||
char
|
||||
to_value_char(char c)
|
||||
{
|
||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||
static std::array<std::uint8_t, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 32
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 48
|
||||
64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 64
|
||||
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, // 80
|
||||
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 96
|
||||
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, // 112
|
||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, // 128
|
||||
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 144
|
||||
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, // 160
|
||||
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, // 176
|
||||
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, // 192
|
||||
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, // 208
|
||||
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 224
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 // 240
|
||||
}};
|
||||
return static_cast<char>(tab[static_cast<std::uint8_t>(c)]);
|
||||
}
|
||||
|
||||
inline
|
||||
std::int8_t
|
||||
unhex(char c)
|
||||
{
|
||||
static std::array<std::int8_t, 256> constexpr tab = {{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 48
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 112
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
struct parser_str_t
|
||||
{
|
||||
@@ -196,6 +65,82 @@ parser_str_t<_>::transfer_encoding[18];
|
||||
|
||||
using parser_str = parser_str_t<>;
|
||||
|
||||
class parser_base
|
||||
{
|
||||
protected:
|
||||
enum state : std::uint8_t
|
||||
{
|
||||
s_dead = 1,
|
||||
|
||||
s_req_start,
|
||||
s_req_method0,
|
||||
s_req_method,
|
||||
s_req_url0,
|
||||
s_req_url,
|
||||
s_req_http,
|
||||
s_req_http_H,
|
||||
s_req_http_HT,
|
||||
s_req_http_HTT,
|
||||
s_req_http_HTTP,
|
||||
s_req_major,
|
||||
s_req_dot,
|
||||
s_req_minor,
|
||||
s_req_cr,
|
||||
s_req_lf,
|
||||
|
||||
s_res_start,
|
||||
s_res_H,
|
||||
s_res_HT,
|
||||
s_res_HTT,
|
||||
s_res_HTTP,
|
||||
s_res_major,
|
||||
s_res_dot,
|
||||
s_res_minor,
|
||||
s_res_space_1,
|
||||
s_res_status0,
|
||||
s_res_status1,
|
||||
s_res_status2,
|
||||
s_res_space_2,
|
||||
s_res_reason0,
|
||||
s_res_reason,
|
||||
s_res_line_lf,
|
||||
s_res_line_done,
|
||||
|
||||
s_header_name0,
|
||||
s_header_name,
|
||||
s_header_value0_lf,
|
||||
s_header_value0_almost_done,
|
||||
s_header_value0,
|
||||
s_header_value,
|
||||
s_header_value_lf,
|
||||
s_header_value_almost_done,
|
||||
s_header_value_unfold,
|
||||
|
||||
s_headers_almost_done,
|
||||
s_headers_done,
|
||||
|
||||
s_chunk_size0,
|
||||
s_chunk_size,
|
||||
s_chunk_ext_name0,
|
||||
s_chunk_ext_name,
|
||||
s_chunk_ext_val,
|
||||
s_chunk_size_lf,
|
||||
s_chunk_data0,
|
||||
s_chunk_data,
|
||||
s_chunk_data_cr,
|
||||
s_chunk_data_lf,
|
||||
|
||||
s_body_identity0,
|
||||
s_body_identity,
|
||||
s_body_identity_eof0,
|
||||
s_body_identity_eof,
|
||||
|
||||
s_complete,
|
||||
s_restart,
|
||||
s_closed_complete
|
||||
};
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
384
src/beast/include/beast/http/detail/rfc7230.hpp
Normal file
384
src/beast/include/beast/http/detail/rfc7230.hpp
Normal file
@@ -0,0 +1,384 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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_DETAIL_RFC7230_HPP
|
||||
#define BEAST_HTTP_DETAIL_RFC7230_HPP
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
inline
|
||||
bool
|
||||
is_digit(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_alpha(char c)
|
||||
{
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 48
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 80
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 112
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)] != 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_text(char c)
|
||||
{
|
||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)] != 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_tchar(char c)
|
||||
{
|
||||
/*
|
||||
tchar = "!" | "#" | "$" | "%" | "&" |
|
||||
"'" | "*" | "+" | "-" | "." |
|
||||
"^" | "_" | "`" | "|" | "~" |
|
||||
DIGIT | ALPHA
|
||||
*/
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)] != 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_qdchar(char c)
|
||||
{
|
||||
/*
|
||||
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
||||
*/
|
||||
static std::array<bool, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_qpchar(char c)
|
||||
{
|
||||
/*
|
||||
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||
obs-text = %x80-FF
|
||||
*/
|
||||
static std::array<bool, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
// converts to lower case,
|
||||
// returns 0 if not a valid token char
|
||||
//
|
||||
inline
|
||||
char
|
||||
to_field_char(char c)
|
||||
{
|
||||
/* token = 1*<any CHAR except CTLs or separators>
|
||||
CHAR = <any US-ASCII character (octets 0 - 127)>
|
||||
sep = "(" | ")" | "<" | ">" | "@"
|
||||
| "," | ";" | ":" | "\" | <">
|
||||
| "/" | "[" | "]" | "?" | "="
|
||||
| "{" | "}" | SP | HT
|
||||
*/
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, '!', 0, '#', '$', '%', '&', '\'', 0, 0, '*', '+', 0, '-', '.', 0,
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
|
||||
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, '^', '_',
|
||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, '|', 0, '~', 0
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
// converts to lower case,
|
||||
// returns 0 if not a valid text char
|
||||
//
|
||||
inline
|
||||
char
|
||||
to_value_char(char c)
|
||||
{
|
||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||
static std::array<std::uint8_t, 256> constexpr tab = {{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 32
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 48
|
||||
64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 64
|
||||
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, // 80
|
||||
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 96
|
||||
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, // 112
|
||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, // 128
|
||||
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 144
|
||||
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, // 160
|
||||
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, // 176
|
||||
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, // 192
|
||||
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, // 208
|
||||
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 224
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 // 240
|
||||
}};
|
||||
return static_cast<char>(tab[static_cast<std::uint8_t>(c)]);
|
||||
}
|
||||
|
||||
inline
|
||||
std::int8_t
|
||||
unhex(char c)
|
||||
{
|
||||
static std::array<std::int8_t, 256> constexpr tab = {{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 48
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 112
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
template<class FwdIt>
|
||||
void
|
||||
skip_ows(FwdIt& it, FwdIt const& end)
|
||||
{
|
||||
while(it != end)
|
||||
{
|
||||
auto const c = *it;
|
||||
if(c != ' ' && c != '\t')
|
||||
break;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
boost::string_ref
|
||||
trim(boost::string_ref const& s)
|
||||
{
|
||||
auto first = s.begin();
|
||||
auto last = s.end();
|
||||
skip_ows(first, last);
|
||||
while(first != last)
|
||||
{
|
||||
auto const c = *std::prev(last);
|
||||
if(c != ' ' && c != '\t')
|
||||
break;
|
||||
--last;
|
||||
}
|
||||
if(first == last)
|
||||
return {};
|
||||
return {&*first,
|
||||
static_cast<std::size_t>(last - first)};
|
||||
}
|
||||
|
||||
struct param_iter
|
||||
{
|
||||
using iter_type = boost::string_ref::const_iterator;
|
||||
|
||||
iter_type it;
|
||||
iter_type begin;
|
||||
iter_type end;
|
||||
std::pair<boost::string_ref, boost::string_ref> v;
|
||||
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return begin == it;
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
increment();
|
||||
};
|
||||
|
||||
template<class>
|
||||
void
|
||||
param_iter::
|
||||
increment()
|
||||
{
|
||||
/*
|
||||
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
||||
ext = token param-list
|
||||
param-list = *( OWS ";" OWS param )
|
||||
param = token OWS "=" OWS ( token / quoted-string )
|
||||
|
||||
quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
|
||||
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
||||
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||
obs-text = %x80-FF
|
||||
|
||||
Example:
|
||||
chunked;a=b;i=j,gzip;windowBits=12
|
||||
x,y
|
||||
*/
|
||||
auto const err =
|
||||
[&]
|
||||
{
|
||||
it = begin;
|
||||
};
|
||||
v.first.clear();
|
||||
v.second.clear();
|
||||
detail::skip_ows(it, end);
|
||||
begin = it;
|
||||
if(it == end)
|
||||
return err();
|
||||
if(*it != ';')
|
||||
return err();
|
||||
++it;
|
||||
detail::skip_ows(it, end);
|
||||
if(it == end)
|
||||
return err();
|
||||
// param
|
||||
if(! detail::is_tchar(*it))
|
||||
return err();
|
||||
auto const p0 = it;
|
||||
for(;;)
|
||||
{
|
||||
++it;
|
||||
if(it == end)
|
||||
return err();
|
||||
if(! detail::is_tchar(*it))
|
||||
break;
|
||||
}
|
||||
auto const p1 = it;
|
||||
detail::skip_ows(it, end);
|
||||
if(it == end)
|
||||
return err();
|
||||
if(*it != '=')
|
||||
return err();
|
||||
++it;
|
||||
detail::skip_ows(it, end);
|
||||
if(it == end)
|
||||
return err();
|
||||
if(*it == '"')
|
||||
{
|
||||
// quoted-string
|
||||
auto const p2 = it;
|
||||
++it;
|
||||
for(;;)
|
||||
{
|
||||
if(it == end)
|
||||
return err();
|
||||
auto c = *it++;
|
||||
if(c == '"')
|
||||
break;
|
||||
if(detail::is_qdchar(c))
|
||||
continue;
|
||||
if(c != '\\')
|
||||
return err();
|
||||
if(it == end)
|
||||
return err();
|
||||
c = *it++;
|
||||
if(! detail::is_qpchar(c))
|
||||
return err();
|
||||
}
|
||||
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
||||
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
||||
}
|
||||
else
|
||||
{
|
||||
// token
|
||||
if(! detail::is_tchar(*it))
|
||||
return err();
|
||||
auto const p2 = it;
|
||||
for(;;)
|
||||
{
|
||||
it++;
|
||||
if(it == end)
|
||||
break;
|
||||
if(! detail::is_tchar(*it))
|
||||
break;
|
||||
}
|
||||
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
||||
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#define BEAST_HTTP_EMPTY_BODY_HPP
|
||||
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
||||
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
||||
|
||||
#include <beast/http/detail/rfc7230.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
@@ -257,12 +259,13 @@ template<class Allocator>
|
||||
void
|
||||
basic_headers<Allocator>::
|
||||
insert(boost::string_ref const& name,
|
||||
boost::string_ref const& value)
|
||||
boost::string_ref value)
|
||||
{
|
||||
value = detail::trim(value);
|
||||
typename set_t::insert_commit_data d;
|
||||
auto const result =
|
||||
set_.insert_check(name, less{}, d);
|
||||
if (result.second)
|
||||
if(result.second)
|
||||
{
|
||||
auto const p = alloc_traits::allocate(
|
||||
this->member(), 1);
|
||||
@@ -284,8 +287,9 @@ template<class Allocator>
|
||||
void
|
||||
basic_headers<Allocator>::
|
||||
replace(boost::string_ref const& name,
|
||||
boost::string_ref const& value)
|
||||
boost::string_ref value)
|
||||
{
|
||||
value = detail::trim(value);
|
||||
erase(name);
|
||||
insert(name, value);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
||||
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
||||
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/http/detail/has_content_length.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <stdexcept>
|
||||
@@ -22,13 +22,11 @@ is_keep_alive(message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
if(msg.version >= 11)
|
||||
{
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "close"))
|
||||
if(token_list{msg.headers["Connection"]}.exists("close"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "keep-alive"))
|
||||
if(token_list{msg.headers["Connection"]}.exists("keep-alive"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -39,8 +37,7 @@ is_upgrade(message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
if(msg.version < 11)
|
||||
return false;
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "upgrade"))
|
||||
if(token_list{msg.headers["Connection"]}.exists("upgrade"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -129,8 +126,7 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
|
||||
throw std::invalid_argument(
|
||||
"prepare called with Content-Length field set");
|
||||
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Transfer-Encoding"], "chunked"))
|
||||
if(token_list{msg.headers["Transfer-Encoding"]}.exists("chunked"))
|
||||
throw std::invalid_argument(
|
||||
"prepare called with Transfer-Encoding: chunked set");
|
||||
|
||||
@@ -175,8 +171,8 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
|
||||
}
|
||||
|
||||
// rfc7230 6.7.
|
||||
if(msg.version < 11 && rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "upgrade"))
|
||||
if(msg.version < 11 && token_list{
|
||||
msg.headers["Connection"]}.exists("upgrade"))
|
||||
throw std::invalid_argument(
|
||||
"invalid version for Connection: upgrade");
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace http {
|
||||
namespace detail {
|
||||
|
||||
template<class Stream,
|
||||
class Streambuf, class Parser, class Handler>
|
||||
class DynamicBuffer, class Parser, class Handler>
|
||||
class parse_op
|
||||
{
|
||||
using alloc_type =
|
||||
@@ -30,7 +30,7 @@ class parse_op
|
||||
struct data
|
||||
{
|
||||
Stream& s;
|
||||
Streambuf& sb;
|
||||
DynamicBuffer& db;
|
||||
Parser& p;
|
||||
Handler h;
|
||||
bool started = false;
|
||||
@@ -39,9 +39,9 @@ class parse_op
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_, Stream& s_,
|
||||
Streambuf& sb_, Parser& p_)
|
||||
DynamicBuffer& sb_, Parser& p_)
|
||||
: s(s_)
|
||||
, sb(sb_)
|
||||
, db(sb_)
|
||||
, p(p_)
|
||||
, h(std::forward<DeducedHandler>(h_))
|
||||
, cont(boost_asio_handler_cont_helpers::
|
||||
@@ -101,9 +101,9 @@ public:
|
||||
};
|
||||
|
||||
template<class Stream,
|
||||
class Streambuf, class Parser, class Handler>
|
||||
class DynamicBuffer, class Parser, class Handler>
|
||||
void
|
||||
parse_op<Stream, Streambuf, Parser, Handler>::
|
||||
parse_op<Stream, DynamicBuffer, Parser, Handler>::
|
||||
operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
||||
{
|
||||
auto& d = *d_;
|
||||
@@ -115,7 +115,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
||||
case 0:
|
||||
{
|
||||
auto const used =
|
||||
d.p.write(d.sb.data(), ec);
|
||||
d.p.write(d.db.data(), ec);
|
||||
if(ec)
|
||||
{
|
||||
// call handler
|
||||
@@ -126,7 +126,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
||||
}
|
||||
if(used > 0)
|
||||
d.started = true;
|
||||
d.sb.consume(used);
|
||||
d.db.consume(used);
|
||||
if(d.p.complete())
|
||||
{
|
||||
// call handler
|
||||
@@ -142,8 +142,8 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
||||
case 1:
|
||||
// read
|
||||
d.state = 2;
|
||||
d.s.async_read_some(d.sb.prepare(
|
||||
read_size_helper(d.sb, 65536)),
|
||||
d.s.async_read_some(d.db.prepare(
|
||||
read_size_helper(d.db, 65536)),
|
||||
std::move(*this));
|
||||
return;
|
||||
|
||||
@@ -172,8 +172,8 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
||||
d.state = 99;
|
||||
break;
|
||||
}
|
||||
d.sb.commit(bytes_transferred);
|
||||
auto const used = d.p.write(d.sb.data(), ec);
|
||||
d.db.commit(bytes_transferred);
|
||||
auto const used = d.p.write(d.db.data(), ec);
|
||||
if(ec)
|
||||
{
|
||||
// call handler
|
||||
@@ -182,7 +182,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
||||
}
|
||||
if(used > 0)
|
||||
d.started = true;
|
||||
d.sb.consume(used);
|
||||
d.db.consume(used);
|
||||
if(d.p.complete())
|
||||
{
|
||||
// call handler
|
||||
@@ -199,7 +199,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Stream, class Streambuf,
|
||||
template<class Stream, class DynamicBuffer,
|
||||
bool isRequest, class Body, class Headers,
|
||||
class Handler>
|
||||
class read_op
|
||||
@@ -216,7 +216,7 @@ class read_op
|
||||
struct data
|
||||
{
|
||||
Stream& s;
|
||||
Streambuf& sb;
|
||||
DynamicBuffer& db;
|
||||
message_type& m;
|
||||
parser_type p;
|
||||
Handler h;
|
||||
@@ -226,9 +226,9 @@ class read_op
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_, Stream& s_,
|
||||
Streambuf& sb_, message_type& m_)
|
||||
DynamicBuffer& sb_, message_type& m_)
|
||||
: s(s_)
|
||||
, sb(sb_)
|
||||
, db(sb_)
|
||||
, m(m_)
|
||||
, h(std::forward<DeducedHandler>(h_))
|
||||
, cont(boost_asio_handler_cont_helpers::
|
||||
@@ -286,11 +286,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Stream, class Streambuf,
|
||||
template<class Stream, class DynamicBuffer,
|
||||
bool isRequest, class Body, class Headers,
|
||||
class Handler>
|
||||
void
|
||||
read_op<Stream, Streambuf, isRequest, Body, Headers, Handler>::
|
||||
read_op<Stream, DynamicBuffer, isRequest, Body, Headers, Handler>::
|
||||
operator()(error_code ec, bool again)
|
||||
{
|
||||
auto& d = *d_;
|
||||
@@ -301,7 +301,7 @@ operator()(error_code ec, bool again)
|
||||
{
|
||||
case 0:
|
||||
d.state = 1;
|
||||
async_parse(d.s, d.sb, d.p, std::move(*this));
|
||||
async_parse(d.s, d.db, d.p, std::move(*this));
|
||||
return;
|
||||
|
||||
case 1:
|
||||
@@ -318,49 +318,49 @@ operator()(error_code ec, bool again)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class SyncReadStream, class Streambuf, class Parser>
|
||||
template<class SyncReadStream, class DynamicBuffer, class Parser>
|
||||
void
|
||||
parse(SyncReadStream& stream,
|
||||
Streambuf& streambuf, Parser& parser)
|
||||
DynamicBuffer& dynabuf, Parser& parser)
|
||||
{
|
||||
static_assert(is_SyncReadStream<SyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_Parser<Parser>::value,
|
||||
"Parser requirements not met");
|
||||
error_code ec;
|
||||
parse(stream, streambuf, parser, ec);
|
||||
parse(stream, dynabuf, parser, ec);
|
||||
if(ec)
|
||||
throw boost::system::system_error{ec};
|
||||
}
|
||||
|
||||
template<class SyncReadStream, class Streambuf, class Parser>
|
||||
template<class SyncReadStream, class DynamicBuffer, class Parser>
|
||||
void
|
||||
parse(SyncReadStream& stream, Streambuf& streambuf,
|
||||
parse(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
Parser& parser, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncReadStream<SyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_Parser<Parser>::value,
|
||||
"Parser requirements not met");
|
||||
bool started = false;
|
||||
for(;;)
|
||||
{
|
||||
auto used =
|
||||
parser.write(streambuf.data(), ec);
|
||||
parser.write(dynabuf.data(), ec);
|
||||
if(ec)
|
||||
return;
|
||||
streambuf.consume(used);
|
||||
dynabuf.consume(used);
|
||||
if(used > 0)
|
||||
started = true;
|
||||
if(parser.complete())
|
||||
break;
|
||||
streambuf.commit(stream.read_some(
|
||||
streambuf.prepare(read_size_helper(
|
||||
streambuf, 65536)), ec));
|
||||
dynabuf.commit(stream.read_some(
|
||||
dynabuf.prepare(read_size_helper(
|
||||
dynabuf, 65536)), ec));
|
||||
if(ec && ec != boost::asio::error::eof)
|
||||
return;
|
||||
if(ec == boost::asio::error::eof)
|
||||
@@ -379,86 +379,86 @@ parse(SyncReadStream& stream, Streambuf& streambuf,
|
||||
}
|
||||
|
||||
template<class AsyncReadStream,
|
||||
class Streambuf, class Parser, class ReadHandler>
|
||||
class DynamicBuffer, class Parser, class ReadHandler>
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
async_parse(AsyncReadStream& stream,
|
||||
Streambuf& streambuf, Parser& parser, ReadHandler&& handler)
|
||||
DynamicBuffer& dynabuf, Parser& parser, ReadHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
|
||||
"AsyncReadStream requirements not met");
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_Parser<Parser>::value,
|
||||
"Parser requirements not met");
|
||||
beast::async_completion<ReadHandler,
|
||||
void(error_code)> completion(handler);
|
||||
detail::parse_op<AsyncReadStream, Streambuf,
|
||||
detail::parse_op<AsyncReadStream, DynamicBuffer,
|
||||
Parser, decltype(completion.handler)>{
|
||||
completion.handler, stream, streambuf, parser};
|
||||
completion.handler, stream, dynabuf, parser};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class SyncReadStream, class Streambuf,
|
||||
template<class SyncReadStream, class DynamicBuffer,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
message_v1<isRequest, Body, Headers>& msg)
|
||||
{
|
||||
static_assert(is_SyncReadStream<SyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_ReadableBody<Body>::value,
|
||||
"ReadableBody requirements not met");
|
||||
error_code ec;
|
||||
read(stream, streambuf, msg, ec);
|
||||
read(stream, dynabuf, msg, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class SyncReadStream, class Streambuf,
|
||||
template<class SyncReadStream, class DynamicBuffer,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
message_v1<isRequest, Body, Headers>& m,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncReadStream<SyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_ReadableBody<Body>::value,
|
||||
"ReadableBody requirements not met");
|
||||
parser_v1<isRequest, Body, Headers> p;
|
||||
parse(stream, streambuf, p, ec);
|
||||
parse(stream, dynabuf, p, ec);
|
||||
if(ec)
|
||||
return;
|
||||
assert(p.complete());
|
||||
m = p.release();
|
||||
}
|
||||
|
||||
template<class AsyncReadStream, class Streambuf,
|
||||
template<class AsyncReadStream, class DynamicBuffer,
|
||||
bool isRequest, class Body, class Headers,
|
||||
class ReadHandler>
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
async_read(AsyncReadStream& stream, Streambuf& streambuf,
|
||||
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
message_v1<isRequest, Body, Headers>& m,
|
||||
ReadHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
|
||||
"AsyncReadStream requirements not met");
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_ReadableBody<Body>::value,
|
||||
"ReadableBody requirements not met");
|
||||
beast::async_completion<ReadHandler,
|
||||
void(error_code)> completion(handler);
|
||||
detail::read_op<AsyncReadStream, Streambuf,
|
||||
detail::read_op<AsyncReadStream, DynamicBuffer,
|
||||
isRequest, Body, Headers, decltype(
|
||||
completion.handler)>{completion.handler,
|
||||
stream, streambuf, m};
|
||||
stream, dynabuf, m};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
|
||||
548
src/beast/include/beast/http/impl/rfc7230.ipp
Normal file
548
src/beast/include/beast/http/impl/rfc7230.ipp
Normal file
@@ -0,0 +1,548 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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_IMPL_RFC7230_IPP
|
||||
#define BEAST_HTTP_IMPL_RFC7230_IPP
|
||||
|
||||
#include <beast/core/detail/ci_char_traits.hpp>
|
||||
#include <beast/http/detail/rfc7230.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
class param_list::const_iterator
|
||||
{
|
||||
using iter_type = boost::string_ref::const_iterator;
|
||||
|
||||
std::string s_;
|
||||
detail::param_iter pi_;
|
||||
|
||||
public:
|
||||
using value_type = param_list::value_type;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type const&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
const_iterator() = default;
|
||||
|
||||
bool
|
||||
operator==(const_iterator const& other) const
|
||||
{
|
||||
return
|
||||
other.pi_.it == pi_.it &&
|
||||
other.pi_.end == pi_.end &&
|
||||
other.pi_.begin == pi_.begin;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return pi_.v;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &*(*this);
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
operator++()
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class param_list;
|
||||
|
||||
const_iterator(iter_type begin, iter_type end)
|
||||
{
|
||||
pi_.it = begin;
|
||||
pi_.begin = begin;
|
||||
pi_.end = end;
|
||||
increment();
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
static
|
||||
std::string
|
||||
unquote(boost::string_ref const& sr);
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
increment();
|
||||
};
|
||||
|
||||
inline
|
||||
auto
|
||||
param_list::
|
||||
begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.begin(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
param_list::
|
||||
end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.end(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
param_list::
|
||||
cbegin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.begin(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
param_list::
|
||||
cend() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.end(), s_.end()};
|
||||
}
|
||||
|
||||
template<class>
|
||||
std::string
|
||||
param_list::const_iterator::
|
||||
unquote(boost::string_ref const& sr)
|
||||
{
|
||||
std::string s;
|
||||
s.reserve(sr.size());
|
||||
auto it = sr.begin() + 1;
|
||||
auto end = sr.end() - 1;
|
||||
while(it != end)
|
||||
{
|
||||
if(*it == '\\')
|
||||
++it;
|
||||
s.push_back(*it);
|
||||
++it;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class>
|
||||
void
|
||||
param_list::const_iterator::
|
||||
increment()
|
||||
{
|
||||
s_.clear();
|
||||
pi_.increment();
|
||||
if(pi_.empty())
|
||||
{
|
||||
pi_.it = pi_.end;
|
||||
pi_.begin = pi_.end;
|
||||
}
|
||||
else if(pi_.v.second.front() == '"')
|
||||
{
|
||||
s_ = unquote(pi_.v.second);
|
||||
pi_.v.second = boost::string_ref{
|
||||
s_.data(), s_.size()};
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ext_list::const_iterator
|
||||
{
|
||||
ext_list::value_type v_;
|
||||
iter_type it_;
|
||||
iter_type begin_;
|
||||
iter_type end_;
|
||||
|
||||
public:
|
||||
using value_type = ext_list::value_type;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type const&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
const_iterator() = default;
|
||||
|
||||
bool
|
||||
operator==(const_iterator const& other) const
|
||||
{
|
||||
return
|
||||
other.it_ == it_ &&
|
||||
other.begin_ == begin_ &&
|
||||
other.end_ == end_;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return v_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &*(*this);
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
operator++()
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ext_list;
|
||||
|
||||
const_iterator(iter_type begin, iter_type end)
|
||||
{
|
||||
it_ = begin;
|
||||
begin_ = begin;
|
||||
end_ = end;
|
||||
increment();
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
increment();
|
||||
};
|
||||
|
||||
inline
|
||||
auto
|
||||
ext_list::
|
||||
begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.begin(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
ext_list::
|
||||
end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.end(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
ext_list::
|
||||
cbegin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.begin(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
ext_list::
|
||||
cend() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.end(), s_.end()};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto
|
||||
ext_list::
|
||||
find(T const& s) ->
|
||||
const_iterator
|
||||
{
|
||||
return std::find_if(begin(), end(),
|
||||
[&s](value_type const& v)
|
||||
{
|
||||
return beast::detail::ci_equal(s, v.first);
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
ext_list::
|
||||
exists(T const& s)
|
||||
{
|
||||
return find(s) != end();
|
||||
}
|
||||
|
||||
template<class>
|
||||
void
|
||||
ext_list::const_iterator::
|
||||
increment()
|
||||
{
|
||||
/*
|
||||
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
||||
ext = token param-list
|
||||
param-list = *( OWS ";" OWS param )
|
||||
param = token OWS "=" OWS ( token / quoted-string )
|
||||
|
||||
chunked;a=b;i=j,gzip;windowBits=12
|
||||
x,y
|
||||
,,,,,chameleon
|
||||
*/
|
||||
auto const err =
|
||||
[&]
|
||||
{
|
||||
it_ = end_;
|
||||
begin_ = end_;
|
||||
};
|
||||
auto need_comma = it_ != begin_;
|
||||
v_.first = {};
|
||||
begin_ = it_;
|
||||
for(;;)
|
||||
{
|
||||
detail::skip_ows(it_, end_);
|
||||
if(it_ == end_)
|
||||
return err();
|
||||
auto const c = *it_;
|
||||
if(detail::is_tchar(c))
|
||||
{
|
||||
if(need_comma)
|
||||
return err();
|
||||
auto const p0 = it_;
|
||||
for(;;)
|
||||
{
|
||||
++it_;
|
||||
if(it_ == end_)
|
||||
break;
|
||||
if(! detail::is_tchar(*it_))
|
||||
break;
|
||||
}
|
||||
v_.first = boost::string_ref{&*p0,
|
||||
static_cast<std::size_t>(it_ - p0)};
|
||||
detail::param_iter pi;
|
||||
pi.it = it_;
|
||||
pi.begin = it_;
|
||||
pi.end = end_;
|
||||
for(;;)
|
||||
{
|
||||
pi.increment();
|
||||
if(pi.empty())
|
||||
break;
|
||||
}
|
||||
v_.second = param_list{boost::string_ref{&*it_,
|
||||
static_cast<std::size_t>(pi.it - it_)}};
|
||||
it_ = pi.it;
|
||||
return;
|
||||
}
|
||||
if(c != ',')
|
||||
return err();
|
||||
need_comma = false;
|
||||
++it_;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class token_list::const_iterator
|
||||
{
|
||||
token_list::value_type v_;
|
||||
iter_type it_;
|
||||
iter_type begin_;
|
||||
iter_type end_;
|
||||
|
||||
public:
|
||||
using value_type = token_list::value_type;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type const&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
const_iterator() = default;
|
||||
|
||||
bool
|
||||
operator==(const_iterator const& other) const
|
||||
{
|
||||
return
|
||||
other.it_ == it_ &&
|
||||
other.begin_ == begin_ &&
|
||||
other.end_ == end_;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return v_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &*(*this);
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
operator++()
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class token_list;
|
||||
|
||||
const_iterator(iter_type begin, iter_type end)
|
||||
{
|
||||
it_ = begin;
|
||||
begin_ = begin;
|
||||
end_ = end;
|
||||
increment();
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
increment();
|
||||
};
|
||||
|
||||
inline
|
||||
auto
|
||||
token_list::
|
||||
begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.begin(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
token_list::
|
||||
end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.end(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
token_list::
|
||||
cbegin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.begin(), s_.end()};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
token_list::
|
||||
cend() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{s_.end(), s_.end()};
|
||||
}
|
||||
|
||||
template<class>
|
||||
void
|
||||
token_list::const_iterator::
|
||||
increment()
|
||||
{
|
||||
/*
|
||||
token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] )
|
||||
*/
|
||||
auto const err =
|
||||
[&]
|
||||
{
|
||||
it_ = end_;
|
||||
begin_ = end_;
|
||||
};
|
||||
auto need_comma = it_ != begin_;
|
||||
v_ = {};
|
||||
begin_ = it_;
|
||||
for(;;)
|
||||
{
|
||||
detail::skip_ows(it_, end_);
|
||||
if(it_ == end_)
|
||||
return err();
|
||||
auto const c = *it_;
|
||||
if(detail::is_tchar(c))
|
||||
{
|
||||
if(need_comma)
|
||||
return err();
|
||||
auto const p0 = it_;
|
||||
for(;;)
|
||||
{
|
||||
++it_;
|
||||
if(it_ == end_)
|
||||
break;
|
||||
if(! detail::is_tchar(*it_))
|
||||
break;
|
||||
}
|
||||
v_ = boost::string_ref{&*p0,
|
||||
static_cast<std::size_t>(it_ - p0)};
|
||||
return;
|
||||
}
|
||||
if(c != ',')
|
||||
return err();
|
||||
need_comma = false;
|
||||
++it_;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
token_list::
|
||||
exists(T const& s)
|
||||
{
|
||||
return std::find_if(begin(), end(),
|
||||
[&s](value_type const& v)
|
||||
{
|
||||
return beast::detail::ci_equal(s, v);
|
||||
}
|
||||
) != end();
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <beast/core/handler_alloc.hpp>
|
||||
#include <beast/core/stream_concepts.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/core/write_streambuf.hpp>
|
||||
#include <beast/core/write_dynabuf.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <condition_variable>
|
||||
@@ -32,51 +32,51 @@ namespace http {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class Streambuf, class Body, class Headers>
|
||||
template<class DynamicBuffer, class Body, class Headers>
|
||||
void
|
||||
write_firstline(Streambuf& streambuf,
|
||||
write_firstline(DynamicBuffer& dynabuf,
|
||||
message_v1<true, Body, Headers> const& msg)
|
||||
{
|
||||
write(streambuf, msg.method);
|
||||
write(streambuf, " ");
|
||||
write(streambuf, msg.url);
|
||||
write(streambuf, " HTTP/");
|
||||
write(streambuf, msg.version / 10);
|
||||
write(streambuf, ".");
|
||||
write(streambuf, msg.version % 10);
|
||||
write(streambuf, "\r\n");
|
||||
write(dynabuf, msg.method);
|
||||
write(dynabuf, " ");
|
||||
write(dynabuf, msg.url);
|
||||
write(dynabuf, " HTTP/");
|
||||
write(dynabuf, msg.version / 10);
|
||||
write(dynabuf, ".");
|
||||
write(dynabuf, msg.version % 10);
|
||||
write(dynabuf, "\r\n");
|
||||
}
|
||||
|
||||
template<class Streambuf, class Body, class Headers>
|
||||
template<class DynamicBuffer, class Body, class Headers>
|
||||
void
|
||||
write_firstline(Streambuf& streambuf,
|
||||
write_firstline(DynamicBuffer& dynabuf,
|
||||
message_v1<false, Body, Headers> const& msg)
|
||||
{
|
||||
write(streambuf, "HTTP/");
|
||||
write(streambuf, msg.version / 10);
|
||||
write(streambuf, ".");
|
||||
write(streambuf, msg.version % 10);
|
||||
write(streambuf, " ");
|
||||
write(streambuf, msg.status);
|
||||
write(streambuf, " ");
|
||||
write(streambuf, msg.reason);
|
||||
write(streambuf, "\r\n");
|
||||
write(dynabuf, "HTTP/");
|
||||
write(dynabuf, msg.version / 10);
|
||||
write(dynabuf, ".");
|
||||
write(dynabuf, msg.version % 10);
|
||||
write(dynabuf, " ");
|
||||
write(dynabuf, msg.status);
|
||||
write(dynabuf, " ");
|
||||
write(dynabuf, msg.reason);
|
||||
write(dynabuf, "\r\n");
|
||||
}
|
||||
|
||||
template<class Streambuf, class FieldSequence>
|
||||
template<class DynamicBuffer, class FieldSequence>
|
||||
void
|
||||
write_fields(Streambuf& streambuf, FieldSequence const& fields)
|
||||
write_fields(DynamicBuffer& dynabuf, FieldSequence const& fields)
|
||||
{
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
//static_assert(is_FieldSequence<FieldSequence>::value,
|
||||
// "FieldSequence requirements not met");
|
||||
for(auto const& field : fields)
|
||||
{
|
||||
write(streambuf, field.name());
|
||||
write(streambuf, ": ");
|
||||
write(streambuf, field.value());
|
||||
write(streambuf, "\r\n");
|
||||
write(dynabuf, field.name());
|
||||
write(dynabuf, ": ");
|
||||
write(dynabuf, field.value());
|
||||
write(dynabuf, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,10 +97,10 @@ struct write_preparation
|
||||
message_v1<isRequest, Body, Headers> const& msg_)
|
||||
: msg(msg_)
|
||||
, w(msg)
|
||||
, chunked(rfc2616::token_in_list(
|
||||
msg.headers["Transfer-Encoding"], "chunked"))
|
||||
, close(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "close") ||
|
||||
, chunked(token_list{
|
||||
msg.headers["Transfer-Encoding"]}.exists("chunked"))
|
||||
, close(token_list{
|
||||
msg.headers["Connection"]}.exists("close") ||
|
||||
(msg.version < 11 && ! msg.headers.exists(
|
||||
"Content-Length")))
|
||||
{
|
||||
@@ -378,17 +378,17 @@ operator()(error_code ec, std::size_t, bool again)
|
||||
d.copy = {};
|
||||
}
|
||||
|
||||
template<class SyncWriteStream, class Streambuf>
|
||||
template<class SyncWriteStream, class DynamicBuffer>
|
||||
class writef0_lambda
|
||||
{
|
||||
Streambuf const& sb_;
|
||||
DynamicBuffer const& sb_;
|
||||
SyncWriteStream& stream_;
|
||||
bool chunked_;
|
||||
error_code& ec_;
|
||||
|
||||
public:
|
||||
writef0_lambda(SyncWriteStream& stream,
|
||||
Streambuf const& sb, bool chunked, error_code& ec)
|
||||
DynamicBuffer const& sb, bool chunked, error_code& ec)
|
||||
: sb_(sb)
|
||||
, stream_(stream)
|
||||
, chunked_(chunked)
|
||||
@@ -548,8 +548,7 @@ async_write(AsyncWriteStream& stream,
|
||||
message_v1<isRequest, Body, Headers> const& msg,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
static_assert(
|
||||
is_AsyncWriteStream<AsyncWriteStream>::value,
|
||||
static_assert(is_AsyncWriteStream<AsyncWriteStream>::value,
|
||||
"AsyncWriteStream requirements not met");
|
||||
static_assert(is_WritableBody<Body>::value,
|
||||
"WritableBody requirements not met");
|
||||
|
||||
@@ -24,12 +24,30 @@ struct request_fields
|
||||
{
|
||||
std::string method;
|
||||
std::string url;
|
||||
|
||||
protected:
|
||||
void
|
||||
swap(request_fields& other)
|
||||
{
|
||||
using std::swap;
|
||||
swap(method, other.method);
|
||||
swap(url, other.url);
|
||||
}
|
||||
};
|
||||
|
||||
struct response_fields
|
||||
{
|
||||
int status;
|
||||
std::string reason;
|
||||
|
||||
protected:
|
||||
void
|
||||
swap(response_fields& other)
|
||||
{
|
||||
using std::swap;
|
||||
swap(status, other.status);
|
||||
swap(reason, other.reason);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
@@ -125,7 +143,14 @@ struct message
|
||||
{
|
||||
}
|
||||
|
||||
/// Swap this message for another message.
|
||||
void
|
||||
swap(message& other);
|
||||
|
||||
private:
|
||||
using base = typename std::conditional<isRequest,
|
||||
detail::request_fields, detail::response_fields>::type;
|
||||
|
||||
template<class... Un, size_t... IUn>
|
||||
message(std::piecewise_construct_t,
|
||||
std::tuple<Un...>& tu, beast::detail::index_sequence<IUn...>)
|
||||
@@ -145,7 +170,26 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
message<isRequest, Body, Headers>::
|
||||
swap(message& other)
|
||||
{
|
||||
using std::swap;
|
||||
base::swap(other);
|
||||
swap(headers, other.headers);
|
||||
swap(body, other.body);
|
||||
}
|
||||
|
||||
/// Swap one message for another message.
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
inline
|
||||
void
|
||||
swap(message<isRequest, Body, Headers>& lhs,
|
||||
message<isRequest, Body, Headers>& rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
/// A typical HTTP request
|
||||
template<class Body,
|
||||
@@ -157,8 +201,6 @@ template<class Body,
|
||||
class Headers = basic_headers<std::allocator<char>>>
|
||||
using response = message<false, Body, Headers>;
|
||||
|
||||
#endif
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -48,9 +48,31 @@ struct message_v1 : message<isRequest, Body, Headers>
|
||||
std::forward<Argn>(argn)...)
|
||||
{
|
||||
}
|
||||
|
||||
/// Swap this message for another message.
|
||||
void
|
||||
swap(message_v1& other);
|
||||
};
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
message_v1<isRequest, Body, Headers>::
|
||||
swap(message_v1& other)
|
||||
{
|
||||
using std::swap;
|
||||
message<isRequest, Body, Headers>::swap(other);
|
||||
swap(version, other.version);
|
||||
}
|
||||
|
||||
/// Swap one message for another message.
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
inline
|
||||
void
|
||||
swap(message_v1<isRequest, Body, Headers>& lhs,
|
||||
message_v1<isRequest, Body, Headers>& rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
/// A typical HTTP/1 request
|
||||
template<class Body,
|
||||
@@ -62,8 +84,6 @@ template<class Body,
|
||||
class Headers = basic_headers<std::allocator<char>>>
|
||||
using response_v1 = message_v1<false, Body, Headers>;
|
||||
|
||||
#endif
|
||||
|
||||
/// Returns `true` if a HTTP/1 message indicates a keep alive
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
|
||||
@@ -23,8 +23,8 @@ enum class parse_error
|
||||
bad_crlf,
|
||||
bad_request,
|
||||
|
||||
bad_status_code,
|
||||
bad_status,
|
||||
bad_reason,
|
||||
|
||||
bad_field,
|
||||
bad_value,
|
||||
@@ -33,7 +33,11 @@ enum class parse_error
|
||||
bad_on_headers_rv,
|
||||
|
||||
invalid_chunk_size,
|
||||
invalid_ext_name,
|
||||
invalid_ext_val,
|
||||
|
||||
headers_too_big,
|
||||
body_too_big,
|
||||
short_read,
|
||||
|
||||
general
|
||||
@@ -60,7 +64,7 @@ public:
|
||||
return "bad method";
|
||||
|
||||
case parse_error::bad_uri:
|
||||
return "bad Request-URI";
|
||||
return "bad request-target";
|
||||
|
||||
case parse_error::bad_version:
|
||||
return "bad HTTP-Version";
|
||||
@@ -69,13 +73,13 @@ public:
|
||||
return "missing CRLF";
|
||||
|
||||
case parse_error::bad_request:
|
||||
return "bad Request-Line";
|
||||
|
||||
case parse_error::bad_status_code:
|
||||
return "bad Status-Code";
|
||||
return "bad reason-phrase";
|
||||
|
||||
case parse_error::bad_status:
|
||||
return "bad Status-Line";
|
||||
return "bad status-code";
|
||||
|
||||
case parse_error::bad_reason:
|
||||
return "bad reason-phrase";
|
||||
|
||||
case parse_error::bad_field:
|
||||
return "bad field token";
|
||||
@@ -95,6 +99,18 @@ public:
|
||||
case parse_error::invalid_chunk_size:
|
||||
return "invalid chunk size";
|
||||
|
||||
case parse_error::invalid_ext_name:
|
||||
return "invalid ext name";
|
||||
|
||||
case parse_error::invalid_ext_val:
|
||||
return "invalid ext val";
|
||||
|
||||
case parse_error::headers_too_big:
|
||||
return "headers size limit exceeded";
|
||||
|
||||
case parse_error::body_too_big:
|
||||
return "body size limit exceeded";
|
||||
|
||||
case parse_error::short_read:
|
||||
return "unexpected end of data";
|
||||
|
||||
|
||||
@@ -124,8 +124,6 @@ private:
|
||||
{
|
||||
if(! value_.empty())
|
||||
{
|
||||
rfc2616::trim_right_in_place(value_);
|
||||
// VFALCO could std::move
|
||||
m_.headers.insert(field_, value_);
|
||||
field_.clear();
|
||||
value_.clear();
|
||||
@@ -174,7 +172,7 @@ private:
|
||||
m_.reason = std::move(this->reason_);
|
||||
}
|
||||
|
||||
int on_headers(error_code&)
|
||||
int on_headers(std::uint64_t, error_code&)
|
||||
{
|
||||
flush();
|
||||
m_.version = 10 * this->http_major() + this->http_minor();
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/async_completion.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
@@ -36,7 +35,7 @@ namespace http {
|
||||
@param stream The stream from which the data is to be read.
|
||||
The type must support the @b `SyncReadStream` concept.
|
||||
|
||||
@param streambuf A `Streambuf` holding additional bytes
|
||||
@param dynabuf A @b `DynamicBuffer` holding additional bytes
|
||||
read by the implementation from the stream. This is both
|
||||
an input and an output parameter; on entry, any data in the
|
||||
stream buffer's input sequence will be given to the parser
|
||||
@@ -47,10 +46,10 @@ namespace http {
|
||||
|
||||
@throws boost::system::system_error on failure.
|
||||
*/
|
||||
template<class SyncReadStream, class Streambuf, class Parser>
|
||||
template<class SyncReadStream, class DynamicBuffer, class Parser>
|
||||
void
|
||||
parse(SyncReadStream& stream,
|
||||
Streambuf& streambuf, Parser& parser);
|
||||
DynamicBuffer& dynabuf, Parser& parser);
|
||||
|
||||
/** Parse a HTTP/1 message from a stream.
|
||||
|
||||
@@ -71,7 +70,7 @@ parse(SyncReadStream& stream,
|
||||
@param stream The stream from which the data is to be read.
|
||||
The type must support the @b `SyncReadStream` concept.
|
||||
|
||||
@param streambuf A `Streambuf` holding additional bytes
|
||||
@param dynabuf A @b `DynamicBuffer` holding additional bytes
|
||||
read by the implementation from the stream. This is both
|
||||
an input and an output parameter; on entry, any data in the
|
||||
stream buffer's input sequence will be given to the parser
|
||||
@@ -82,10 +81,10 @@ parse(SyncReadStream& stream,
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
template<class SyncReadStream, class Streambuf, class Parser>
|
||||
template<class SyncReadStream, class DynamicBuffer, class Parser>
|
||||
void
|
||||
parse(SyncReadStream& stream,
|
||||
Streambuf& streambuf, Parser& parser, error_code& ec);
|
||||
DynamicBuffer& dynabuf, Parser& parser, error_code& ec);
|
||||
|
||||
/** Start an asynchronous operation to parse a HTTP/1 message from a stream.
|
||||
|
||||
@@ -106,7 +105,7 @@ parse(SyncReadStream& stream,
|
||||
@param stream The stream from which the data is to be read.
|
||||
The type must support the @b `AsyncReadStream` concept.
|
||||
|
||||
@param streambuf A `Streambuf` holding additional bytes
|
||||
@param dynabuf A @b `DynamicBuffer` holding additional bytes
|
||||
read by the implementation from the stream. This is both
|
||||
an input and an output parameter; on entry, any data in the
|
||||
stream buffer's input sequence will be given to the parser
|
||||
@@ -128,14 +127,14 @@ parse(SyncReadStream& stream,
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class AsyncReadStream,
|
||||
class Streambuf, class Parser, class ReadHandler>
|
||||
class DynamicBuffer, class Parser, class ReadHandler>
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_parse(AsyncReadStream& stream, Streambuf& streambuf,
|
||||
async_parse(AsyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
Parser& parser, ReadHandler&& handler);
|
||||
|
||||
/** Read a HTTP/1 message from a stream.
|
||||
@@ -157,7 +156,7 @@ async_parse(AsyncReadStream& stream, Streambuf& streambuf,
|
||||
@param stream The stream from which the data is to be read.
|
||||
The type must support the @b `SyncReadStream` concept.
|
||||
|
||||
@param streambuf A `Streambuf` holding additional bytes
|
||||
@param dynabuf A @b `DynamicBuffer` holding additional bytes
|
||||
read by the implementation from the stream. This is both
|
||||
an input and an output parameter; on entry, any data in the
|
||||
stream buffer's input sequence will be given to the parser
|
||||
@@ -168,10 +167,10 @@ async_parse(AsyncReadStream& stream, Streambuf& streambuf,
|
||||
|
||||
@throws boost::system::system_error Thrown on failure.
|
||||
*/
|
||||
template<class SyncReadStream, class Streambuf,
|
||||
template<class SyncReadStream, class DynamicBuffer,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
message_v1<isRequest, Body, Headers>& msg);
|
||||
|
||||
/** Read a HTTP/1 message from a stream.
|
||||
@@ -193,7 +192,7 @@ read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
@param stream The stream from which the data is to be read.
|
||||
The type must support the @b `SyncReadStream` concept.
|
||||
|
||||
@param streambuf A `Streambuf` holding additional bytes
|
||||
@param dynabuf A @b `DynamicBuffer` holding additional bytes
|
||||
read by the implementation from the stream. This is both
|
||||
an input and an output parameter; on entry, any data in the
|
||||
stream buffer's input sequence will be given to the parser
|
||||
@@ -204,10 +203,10 @@ read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
template<class SyncReadStream, class Streambuf,
|
||||
template<class SyncReadStream, class DynamicBuffer,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
message_v1<isRequest, Body, Headers>& msg,
|
||||
error_code& ec);
|
||||
|
||||
@@ -229,7 +228,7 @@ read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
@param stream The stream to read the message from.
|
||||
The type must support the @b `AsyncReadStream` concept.
|
||||
|
||||
@param streambuf A `Streambuf` holding additional bytes
|
||||
@param dynabuf A @b `DynamicBuffer` holding additional bytes
|
||||
read by the implementation from the stream. This is both
|
||||
an input and an output parameter; on entry, any data in the
|
||||
stream buffer's input sequence will be given to the parser
|
||||
@@ -249,7 +248,7 @@ read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class AsyncReadStream, class Streambuf,
|
||||
template<class AsyncReadStream, class DynamicBuffer,
|
||||
bool isRequest, class Body, class Headers,
|
||||
class ReadHandler>
|
||||
#if GENERATING_DOCS
|
||||
@@ -258,7 +257,7 @@ void_or_deduced
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_read(AsyncReadStream& stream, Streambuf& streambuf,
|
||||
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
message_v1<isRequest, Body, Headers>& msg,
|
||||
ReadHandler&& handler);
|
||||
|
||||
|
||||
@@ -1,464 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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_RFC2616_HPP
|
||||
#define BEAST_HTTP_RFC2616_HPP
|
||||
|
||||
#include <boost/range/algorithm/equal.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <tuple> // for std::tie, remove ASAP
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
/** Routines for performing RFC2616 compliance.
|
||||
RFC2616:
|
||||
Hypertext Transfer Protocol -- HTTP/1.1
|
||||
http://www.w3.org/Protocols/rfc2616/rfc2616
|
||||
*/
|
||||
namespace rfc2616 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct ci_equal_pred
|
||||
{
|
||||
bool operator()(char c1, char c2)
|
||||
{
|
||||
// VFALCO TODO Use a table lookup here
|
||||
return std::tolower(c1) == std::tolower(c2);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
/** Returns `true` if `c` is linear white space.
|
||||
|
||||
This excludes the CRLF sequence allowed for line continuations.
|
||||
*/
|
||||
inline
|
||||
bool
|
||||
is_lws(char c)
|
||||
{
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is any whitespace character. */
|
||||
inline
|
||||
bool
|
||||
is_white(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ' ': case '\f': case '\n':
|
||||
case '\r': case '\t': case '\v':
|
||||
return true;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is a control character. */
|
||||
inline
|
||||
bool
|
||||
is_control(char c)
|
||||
{
|
||||
return c <= 31 || c >= 127;
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is a separator. */
|
||||
inline
|
||||
bool
|
||||
is_separator(char c)
|
||||
{
|
||||
// VFALCO Could use a static table
|
||||
switch (c)
|
||||
{
|
||||
case '(': case ')': case '<': case '>': case '@':
|
||||
case ',': case ';': case ':': case '\\': case '"':
|
||||
case '{': case '}': case ' ': case '\t':
|
||||
return true;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is a character. */
|
||||
inline
|
||||
bool
|
||||
is_char(char c)
|
||||
{
|
||||
return c >= 0 && c <= 127;
|
||||
}
|
||||
|
||||
template <class FwdIter>
|
||||
FwdIter
|
||||
trim_left (FwdIter first, FwdIter last)
|
||||
{
|
||||
return std::find_if_not (first, last,
|
||||
is_white);
|
||||
}
|
||||
|
||||
template <class FwdIter>
|
||||
FwdIter
|
||||
trim_right (FwdIter first, FwdIter last)
|
||||
{
|
||||
if (first == last)
|
||||
return last;
|
||||
do
|
||||
{
|
||||
--last;
|
||||
if (! is_white (*last))
|
||||
return ++last;
|
||||
}
|
||||
while (last != first);
|
||||
return first;
|
||||
}
|
||||
|
||||
template <class CharT, class Traits, class Allocator>
|
||||
void
|
||||
trim_right_in_place (std::basic_string <
|
||||
CharT, Traits, Allocator>& s)
|
||||
{
|
||||
s.resize (std::distance (s.begin(),
|
||||
trim_right (s.begin(), s.end())));
|
||||
}
|
||||
|
||||
template <class FwdIter>
|
||||
std::pair <FwdIter, FwdIter>
|
||||
trim (FwdIter first, FwdIter last)
|
||||
{
|
||||
first = trim_left (first, last);
|
||||
last = trim_right (first, last);
|
||||
return std::make_pair (first, last);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String
|
||||
trim (String const& s)
|
||||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
auto first = begin(s);
|
||||
auto last = end(s);
|
||||
std::tie (first, last) = trim (first, last);
|
||||
return { first, last };
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String
|
||||
trim_right (String const& s)
|
||||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
auto first (begin(s));
|
||||
auto last (end(s));
|
||||
last = trim_right (first, last);
|
||||
return { first, last };
|
||||
}
|
||||
|
||||
inline
|
||||
std::string
|
||||
trim (std::string const& s)
|
||||
{
|
||||
return trim <std::string> (s);
|
||||
}
|
||||
|
||||
/** Parse a character sequence of values separated by commas.
|
||||
Double quotes and escape sequences will be converted. Excess white
|
||||
space, commas, double quotes, and empty elements are not copied.
|
||||
Format:
|
||||
#(token|quoted-string)
|
||||
Reference:
|
||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2
|
||||
*/
|
||||
template <class FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename
|
||||
std::iterator_traits<FwdIt>::value_type>>,
|
||||
class Char>
|
||||
Result
|
||||
split(FwdIt first, FwdIt last, Char delim)
|
||||
{
|
||||
Result result;
|
||||
using string = typename Result::value_type;
|
||||
FwdIt iter = first;
|
||||
string e;
|
||||
while (iter != last)
|
||||
{
|
||||
if (*iter == '"')
|
||||
{
|
||||
// quoted-string
|
||||
++iter;
|
||||
while (iter != last)
|
||||
{
|
||||
if (*iter == '"')
|
||||
{
|
||||
++iter;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*iter == '\\')
|
||||
{
|
||||
// quoted-pair
|
||||
++iter;
|
||||
if (iter != last)
|
||||
e.append (1, *iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
// qdtext
|
||||
e.append (1, *iter++);
|
||||
}
|
||||
}
|
||||
if (! e.empty())
|
||||
{
|
||||
result.emplace_back(std::move(e));
|
||||
e.clear();
|
||||
}
|
||||
}
|
||||
else if (*iter == delim)
|
||||
{
|
||||
e = trim_right (e);
|
||||
if (! e.empty())
|
||||
{
|
||||
result.emplace_back(std::move(e));
|
||||
e.clear();
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
else if (is_lws (*iter))
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.append (1, *iter++);
|
||||
}
|
||||
}
|
||||
|
||||
if (! e.empty())
|
||||
{
|
||||
e = trim_right (e);
|
||||
if (! e.empty())
|
||||
result.emplace_back(std::move(e));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename std::iterator_traits<
|
||||
FwdIt>::value_type>>>
|
||||
Result
|
||||
split_commas(FwdIt first, FwdIt last)
|
||||
{
|
||||
return split(first, last, ',');
|
||||
}
|
||||
|
||||
template <class Result = std::vector<std::string>>
|
||||
Result
|
||||
split_commas(boost::string_ref const& s)
|
||||
{
|
||||
return split_commas(s.begin(), s.end());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Iterates through a comma separated list.
|
||||
|
||||
Meets the requirements of ForwardIterator.
|
||||
|
||||
List defined in rfc2616 2.1.
|
||||
|
||||
@note Values returned may contain backslash escapes.
|
||||
*/
|
||||
class list_iterator
|
||||
{
|
||||
using iter_type = boost::string_ref::const_iterator;
|
||||
|
||||
iter_type it_;
|
||||
iter_type end_;
|
||||
boost::string_ref value_;
|
||||
|
||||
public:
|
||||
using value_type = boost::string_ref;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type const&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category =
|
||||
std::forward_iterator_tag;
|
||||
|
||||
list_iterator(iter_type begin, iter_type end)
|
||||
: it_(begin)
|
||||
, end_(end)
|
||||
{
|
||||
if(it_ != end_)
|
||||
increment();
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(list_iterator const& other) const
|
||||
{
|
||||
return other.it_ == it_ && other.end_ == end_
|
||||
&& other.value_.size() == value_.size();
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(list_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &*(*this);
|
||||
}
|
||||
|
||||
list_iterator&
|
||||
operator++()
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
list_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
template<class = void>
|
||||
void
|
||||
increment();
|
||||
};
|
||||
|
||||
template<class>
|
||||
void
|
||||
list_iterator::increment()
|
||||
{
|
||||
value_.clear();
|
||||
while(it_ != end_)
|
||||
{
|
||||
if(*it_ == '"')
|
||||
{
|
||||
// quoted-string
|
||||
++it_;
|
||||
if(it_ == end_)
|
||||
return;
|
||||
if(*it_ != '"')
|
||||
{
|
||||
auto start = it_;
|
||||
for(;;)
|
||||
{
|
||||
++it_;
|
||||
if(it_ == end_)
|
||||
{
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
return;
|
||||
}
|
||||
if(*it_ == '"')
|
||||
{
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
++it_;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
++it_;
|
||||
}
|
||||
else if(*it_ == ',')
|
||||
{
|
||||
it_++;
|
||||
continue;
|
||||
}
|
||||
else if(is_lws(*it_))
|
||||
{
|
||||
++it_;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto start = it_;
|
||||
for(;;)
|
||||
{
|
||||
++it_;
|
||||
if(it_ == end_ ||
|
||||
*it_ == ',' ||
|
||||
is_lws(*it_))
|
||||
{
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if two strings are equal.
|
||||
|
||||
A case-insensitive comparison is used.
|
||||
*/
|
||||
inline
|
||||
bool
|
||||
ci_equal(boost::string_ref s1, boost::string_ref s2)
|
||||
{
|
||||
return boost::range::equal(s1, s2,
|
||||
detail::ci_equal_pred{});
|
||||
}
|
||||
|
||||
/** Returns a range representing the list. */
|
||||
inline
|
||||
boost::iterator_range<list_iterator>
|
||||
make_list(boost::string_ref const& field)
|
||||
{
|
||||
return boost::iterator_range<list_iterator>{
|
||||
list_iterator{field.begin(), field.end()},
|
||||
list_iterator{field.end(), field.end()}};
|
||||
}
|
||||
|
||||
/** Returns true if the specified token exists in the list.
|
||||
|
||||
A case-insensitive comparison is used.
|
||||
*/
|
||||
template<class = void>
|
||||
bool
|
||||
token_in_list(boost::string_ref const& value,
|
||||
boost::string_ref const& token)
|
||||
{
|
||||
for(auto const& item : make_list(value))
|
||||
if(ci_equal(item, token))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // rfc2616
|
||||
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,16 +8,238 @@
|
||||
#ifndef BEAST_HTTP_RFC7230_HPP
|
||||
#define BEAST_HTTP_RFC7230_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <beast/http/detail/rfc7230.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace rfc7230 {
|
||||
namespace http {
|
||||
|
||||
/** A list of parameters in a HTTP extension field value.
|
||||
|
||||
This container allows iteration of the parameter list
|
||||
in a HTTP extension. The parameter list is a series
|
||||
of "name = value" pairs with each pair starting with
|
||||
a semicolon.
|
||||
|
||||
} // rfc7230
|
||||
BNF:
|
||||
@code
|
||||
param-list = *( OWS ";" OWS param )
|
||||
param = token OWS "=" OWS ( token / quoted-string )
|
||||
@endcode
|
||||
|
||||
If a parsing error is encountered while iterating the string,
|
||||
the behavior of the container will be as if a string containing
|
||||
only characters up to but excluding the first invalid character
|
||||
was used to construct the list.
|
||||
*/
|
||||
class param_list
|
||||
{
|
||||
boost::string_ref s_;
|
||||
|
||||
public:
|
||||
/** The type of each element in the list.
|
||||
|
||||
The first string in the pair is the name of the
|
||||
parameter, and the second string in the pair is its value.
|
||||
*/
|
||||
using value_type =
|
||||
std::pair<boost::string_ref, boost::string_ref>;
|
||||
|
||||
/// A constant iterator to the list
|
||||
#if GENERATING_DOCS
|
||||
using const_iterator = implementation_defined;
|
||||
#else
|
||||
class const_iterator;
|
||||
#endif
|
||||
|
||||
/// Default constructor.
|
||||
param_list() = default;
|
||||
|
||||
/** Construct a list.
|
||||
|
||||
@param s A string containing the list contents. The string
|
||||
must remain valid for the lifetime of the container.
|
||||
*/
|
||||
explicit
|
||||
param_list(boost::string_ref const& s)
|
||||
: s_(s)
|
||||
{
|
||||
}
|
||||
|
||||
/// Return a const iterator to the beginning of the list
|
||||
const_iterator begin() const;
|
||||
|
||||
/// Return a const iterator to the end of the list
|
||||
const_iterator end() const;
|
||||
|
||||
/// Return a const iterator to the beginning of the list
|
||||
const_iterator cbegin() const;
|
||||
|
||||
/// Return a const iterator to the end of the list
|
||||
const_iterator cend() const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A list of extensions in a comma separated HTTP field value.
|
||||
|
||||
This container allows iteration of the extensions in a HTTP
|
||||
field value. The extension list is a comma separated list of
|
||||
token parameter list pairs.
|
||||
|
||||
BNF:
|
||||
@code
|
||||
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
||||
ext = token param-list
|
||||
param-list = *( OWS ";" OWS param )
|
||||
param = token OWS "=" OWS ( token / quoted-string )
|
||||
@endcode
|
||||
|
||||
If a parsing error is encountered while iterating the string,
|
||||
the behavior of the container will be as if a string containing
|
||||
only characters up to but excluding the first invalid character
|
||||
was used to construct the list.
|
||||
*/
|
||||
class ext_list
|
||||
{
|
||||
using iter_type = boost::string_ref::const_iterator;
|
||||
|
||||
boost::string_ref s_;
|
||||
|
||||
public:
|
||||
/** The type of each element in the list.
|
||||
|
||||
The first element of the pair is the extension token, and the
|
||||
second element of the pair is an iterable container holding the
|
||||
extension's name/value parameters.
|
||||
*/
|
||||
using value_type = std::pair<boost::string_ref, param_list>;
|
||||
|
||||
/// A constant iterator to the list
|
||||
#if GENERATING_DOCS
|
||||
using const_iterator = implementation_defined;
|
||||
#else
|
||||
class const_iterator;
|
||||
#endif
|
||||
|
||||
/** Construct a list.
|
||||
|
||||
@param s A string containing the list contents. The string
|
||||
must remain valid for the lifetime of the container.
|
||||
*/
|
||||
explicit
|
||||
ext_list(boost::string_ref const& s)
|
||||
: s_(s)
|
||||
{
|
||||
}
|
||||
|
||||
/// Return a const iterator to the beginning of the list
|
||||
const_iterator begin() const;
|
||||
|
||||
/// Return a const iterator to the end of the list
|
||||
const_iterator end() const;
|
||||
|
||||
/// Return a const iterator to the beginning of the list
|
||||
const_iterator cbegin() const;
|
||||
|
||||
/// Return a const iterator to the end of the list
|
||||
const_iterator cend() const;
|
||||
|
||||
/** Find a token in the list.
|
||||
|
||||
@param s The token to find. A case-insensitive comparison is used.
|
||||
|
||||
@return An iterator to the matching token, or `end()` if no
|
||||
token exists.
|
||||
*/
|
||||
template<class T>
|
||||
const_iterator
|
||||
find(T const& s);
|
||||
|
||||
/** Return `true` if a token is present in the list.
|
||||
|
||||
@param s The token to find. A case-insensitive comparison is used.
|
||||
*/
|
||||
template<class T>
|
||||
bool
|
||||
exists(T const& s);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A list of tokens in a comma separated HTTP field value.
|
||||
|
||||
This container allows iteration of the extensions in a HTTP
|
||||
field value. The extension list is a comma separated list of
|
||||
token parameter list pairs.
|
||||
|
||||
BNF:
|
||||
@code
|
||||
token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] )
|
||||
@endcode
|
||||
|
||||
If a parsing error is encountered while iterating the string,
|
||||
the behavior of the container will be as if a string containing
|
||||
only characters up to but excluding the first invalid character
|
||||
was used to construct the list.
|
||||
*/
|
||||
class token_list
|
||||
{
|
||||
using iter_type = boost::string_ref::const_iterator;
|
||||
|
||||
boost::string_ref s_;
|
||||
|
||||
public:
|
||||
/** The type of each element in the token list.
|
||||
|
||||
The first element of the pair is the extension token, and the
|
||||
second element of the pair is an iterable container holding the
|
||||
extension's name/value parameters.
|
||||
*/
|
||||
using value_type = boost::string_ref;
|
||||
|
||||
/// A constant iterator to the list
|
||||
#if GENERATING_DOCS
|
||||
using const_iterator = implementation_defined;
|
||||
#else
|
||||
class const_iterator;
|
||||
#endif
|
||||
|
||||
/** Construct a list.
|
||||
|
||||
@param s A string containing the list contents. The string
|
||||
must remain valid for the lifetime of the container.
|
||||
*/
|
||||
explicit
|
||||
token_list(boost::string_ref const& s)
|
||||
: s_(s)
|
||||
{
|
||||
}
|
||||
|
||||
/// Return a const iterator to the beginning of the list
|
||||
const_iterator begin() const;
|
||||
|
||||
/// Return a const iterator to the end of the list
|
||||
const_iterator end() const;
|
||||
|
||||
/// Return a const iterator to the beginning of the list
|
||||
const_iterator cbegin() const;
|
||||
|
||||
/// Return a const iterator to the end of the list
|
||||
const_iterator cend() const;
|
||||
|
||||
/** Return `true` if a token is present in the list.
|
||||
|
||||
@param s The token to find. A case-insensitive comparison is used.
|
||||
*/
|
||||
template<class T>
|
||||
bool
|
||||
exists(T const& s);
|
||||
};
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#include <beast/http/impl/rfc7230.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -8,91 +8,17 @@
|
||||
#ifndef BEAST_HTTP_STREAMBUF_BODY_HPP
|
||||
#define BEAST_HTTP_STREAMBUF_BODY_HPP
|
||||
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/http/basic_dynabuf_body.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** A message body represented by a Streambuf
|
||||
/** A message body represented by a @ref streambuf
|
||||
|
||||
Meets the requirements of @b `Body`.
|
||||
*/
|
||||
template<class Streambuf>
|
||||
struct basic_streambuf_body
|
||||
{
|
||||
/// The type of the `message::body` member
|
||||
using value_type = Streambuf;
|
||||
|
||||
#if GENERATING_DOCS
|
||||
private:
|
||||
#endif
|
||||
|
||||
class reader
|
||||
{
|
||||
value_type& sb_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
reader(message<isRequest,
|
||||
basic_streambuf_body, Headers>& m) noexcept
|
||||
: sb_(m.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
write(void const* data,
|
||||
std::size_t size, error_code&) noexcept
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
sb_.commit(buffer_copy(
|
||||
sb_.prepare(size), buffer(data, size)));
|
||||
}
|
||||
};
|
||||
|
||||
class writer
|
||||
{
|
||||
Streambuf const& body_;
|
||||
|
||||
public:
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
writer(message<
|
||||
isRequest, basic_streambuf_body, Headers> const& m)
|
||||
: body_(m.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
{
|
||||
return body_.size();
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
{
|
||||
write(body_.data());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
using streambuf_body = basic_streambuf_body<streambuf>;
|
||||
using streambuf_body = basic_dynabuf_body<streambuf>;
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#define BEAST_HTTP_STRING_BODY_HPP
|
||||
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
// BEAST_VERSION / 100 % 1000 is the minor version
|
||||
// BEAST_VERSION / 100000 is the major version
|
||||
//
|
||||
#define BEAST_VERSION 100000
|
||||
#define BEAST_VERSION 100006
|
||||
|
||||
#define BEAST_VERSION_STRING "1.0.0-b5"
|
||||
#define BEAST_VERSION_STRING "1.0.0-b6"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -117,11 +117,11 @@ is_valid(close_code::value code)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Write frame header to streambuf
|
||||
// Write frame header to dynamic buffer
|
||||
//
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
write(Streambuf& sb, frame_header const& fh)
|
||||
write(DynamicBuffer& db, frame_header const& fh)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
@@ -159,24 +159,24 @@ write(Streambuf& sb, frame_header const& fh)
|
||||
native_to_little_uint32(fh.key, &b[n]);
|
||||
n += 4;
|
||||
}
|
||||
sb.commit(buffer_copy(
|
||||
sb.prepare(n), buffer(b)));
|
||||
db.commit(buffer_copy(
|
||||
db.prepare(n), buffer(b)));
|
||||
}
|
||||
|
||||
// Read fixed frame header
|
||||
// Requires at least 2 bytes
|
||||
//
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
std::size_t
|
||||
read_fh1(frame_header& fh, Streambuf& sb,
|
||||
read_fh1(frame_header& fh, DynamicBuffer& db,
|
||||
role_type role, close_code::value& code)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
std::uint8_t b[2];
|
||||
assert(buffer_size(sb.data()) >= sizeof(b));
|
||||
sb.consume(buffer_copy(buffer(b), sb.data()));
|
||||
assert(buffer_size(db.data()) >= sizeof(b));
|
||||
db.consume(buffer_copy(buffer(b), db.data()));
|
||||
std::size_t need;
|
||||
fh.len = b[1] & 0x7f;
|
||||
switch(fh.len)
|
||||
@@ -236,9 +236,9 @@ read_fh1(frame_header& fh, Streambuf& sb,
|
||||
|
||||
// Decode variable frame header from stream
|
||||
//
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
read_fh2(frame_header& fh, Streambuf& sb,
|
||||
read_fh2(frame_header& fh, DynamicBuffer& db,
|
||||
role_type role, close_code::value& code)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
@@ -250,8 +250,8 @@ read_fh2(frame_header& fh, Streambuf& sb,
|
||||
case 126:
|
||||
{
|
||||
std::uint8_t b[2];
|
||||
assert(buffer_size(sb.data()) >= sizeof(b));
|
||||
sb.consume(buffer_copy(buffer(b), sb.data()));
|
||||
assert(buffer_size(db.data()) >= sizeof(b));
|
||||
db.consume(buffer_copy(buffer(b), db.data()));
|
||||
fh.len = big_uint16_to_native(&b[0]);
|
||||
// length not canonical
|
||||
if(fh.len < 126)
|
||||
@@ -264,8 +264,8 @@ read_fh2(frame_header& fh, Streambuf& sb,
|
||||
case 127:
|
||||
{
|
||||
std::uint8_t b[8];
|
||||
assert(buffer_size(sb.data()) >= sizeof(b));
|
||||
sb.consume(buffer_copy(buffer(b), sb.data()));
|
||||
assert(buffer_size(db.data()) >= sizeof(b));
|
||||
db.consume(buffer_copy(buffer(b), db.data()));
|
||||
fh.len = big_uint64_to_native(&b[0]);
|
||||
// length not canonical
|
||||
if(fh.len < 65536)
|
||||
@@ -279,8 +279,8 @@ read_fh2(frame_header& fh, Streambuf& sb,
|
||||
if(fh.mask)
|
||||
{
|
||||
std::uint8_t b[4];
|
||||
assert(buffer_size(sb.data()) >= sizeof(b));
|
||||
sb.consume(buffer_copy(buffer(b), sb.data()));
|
||||
assert(buffer_size(db.data()) >= sizeof(b));
|
||||
db.consume(buffer_copy(buffer(b), db.data()));
|
||||
fh.key = little_uint32_to_native(&b[0]);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
@@ -107,15 +106,13 @@ protected:
|
||||
void
|
||||
prepare_fh(close_code::value& code);
|
||||
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
write_close(Streambuf& sb,
|
||||
close_reason const& rc);
|
||||
write_close(DynamicBuffer& db, close_reason const& rc);
|
||||
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
write_ping(Streambuf& sb, opcode op,
|
||||
ping_data const& data);
|
||||
write_ping(DynamicBuffer& db, opcode op, ping_data const& data);
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace websocket {
|
||||
// processes any received control frames.
|
||||
//
|
||||
template<class NextLayer>
|
||||
template<class Streambuf, class Handler>
|
||||
template<class DynamicBuffer, class Handler>
|
||||
class stream<NextLayer>::read_frame_op
|
||||
{
|
||||
using alloc_type =
|
||||
@@ -35,27 +35,27 @@ class stream<NextLayer>::read_frame_op
|
||||
using fmb_type =
|
||||
typename fb_type::mutable_buffers_type;
|
||||
|
||||
using smb_type =
|
||||
typename Streambuf::mutable_buffers_type;
|
||||
using dmb_type =
|
||||
typename DynamicBuffer::mutable_buffers_type;
|
||||
|
||||
struct data : op
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
frame_info& fi;
|
||||
Streambuf& sb;
|
||||
DynamicBuffer& db;
|
||||
Handler h;
|
||||
fb_type fb;
|
||||
boost::optional<smb_type> smb;
|
||||
boost::optional<dmb_type> dmb;
|
||||
boost::optional<fmb_type> fmb;
|
||||
bool cont;
|
||||
int state = 0;
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_, stream<NextLayer>& ws_,
|
||||
frame_info& fi_, Streambuf& sb_)
|
||||
frame_info& fi_, DynamicBuffer& sb_)
|
||||
: ws(ws_)
|
||||
, fi(fi_)
|
||||
, sb(sb_)
|
||||
, db(sb_)
|
||||
, h(std::forward<DeducedHandler>(h_))
|
||||
, cont(boost_asio_handler_cont_helpers::
|
||||
is_continuation(h))
|
||||
@@ -127,9 +127,9 @@ public:
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Buffers, class Handler>
|
||||
template<class DynamicBuffer, class Handler>
|
||||
void
|
||||
stream<NextLayer>::read_frame_op<Buffers, Handler>::
|
||||
stream<NextLayer>::read_frame_op<DynamicBuffer, Handler>::
|
||||
operator()(error_code ec, std::size_t bytes_transferred)
|
||||
{
|
||||
auto& d = *d_;
|
||||
@@ -139,9 +139,9 @@ operator()(error_code ec, std::size_t bytes_transferred)
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Buffers, class Handler>
|
||||
template<class DynamicBuffer, class Handler>
|
||||
void
|
||||
stream<NextLayer>::read_frame_op<Buffers, Handler>::
|
||||
stream<NextLayer>::read_frame_op<DynamicBuffer, Handler>::
|
||||
operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
{
|
||||
enum
|
||||
@@ -187,18 +187,18 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
|
||||
case do_read_payload:
|
||||
d.state = do_read_payload + 1;
|
||||
d.smb = d.sb.prepare(
|
||||
d.dmb = d.db.prepare(
|
||||
detail::clamp(d.ws.rd_need_));
|
||||
// receive payload data
|
||||
d.ws.stream_.async_read_some(
|
||||
*d.smb, std::move(*this));
|
||||
*d.dmb, std::move(*this));
|
||||
return;
|
||||
|
||||
case do_read_payload + 1:
|
||||
{
|
||||
d.ws.rd_need_ -= bytes_transferred;
|
||||
auto const pb = prepare_buffers(
|
||||
bytes_transferred, *d.smb);
|
||||
bytes_transferred, *d.dmb);
|
||||
if(d.ws.rd_fh_.mask)
|
||||
detail::mask_inplace(pb, d.ws.rd_key_);
|
||||
if(d.ws.rd_opcode_ == opcode::text)
|
||||
@@ -213,7 +213,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
break;
|
||||
}
|
||||
}
|
||||
d.sb.commit(bytes_transferred);
|
||||
d.db.commit(bytes_transferred);
|
||||
if(d.ws.rd_need_ > 0)
|
||||
{
|
||||
d.state = do_read_payload;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace websocket {
|
||||
// read an entire message
|
||||
//
|
||||
template<class NextLayer>
|
||||
template<class Streambuf, class Handler>
|
||||
template<class DynamicBuffer, class Handler>
|
||||
class stream<NextLayer>::read_op
|
||||
{
|
||||
using alloc_type =
|
||||
@@ -27,7 +27,7 @@ class stream<NextLayer>::read_op
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
opcode& op;
|
||||
Streambuf& sb;
|
||||
DynamicBuffer& db;
|
||||
Handler h;
|
||||
frame_info fi;
|
||||
bool cont;
|
||||
@@ -36,10 +36,10 @@ class stream<NextLayer>::read_op
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_,
|
||||
stream<NextLayer>& ws_, opcode& op_,
|
||||
Streambuf& sb_)
|
||||
DynamicBuffer& sb_)
|
||||
: ws(ws_)
|
||||
, op(op_)
|
||||
, sb(sb_)
|
||||
, db(sb_)
|
||||
, h(std::forward<DeducedHandler>(h_))
|
||||
, cont(boost_asio_handler_cont_helpers::
|
||||
is_continuation(h))
|
||||
@@ -98,9 +98,9 @@ public:
|
||||
};
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Streambuf, class Handler>
|
||||
template<class DynamicBuffer, class Handler>
|
||||
void
|
||||
stream<NextLayer>::read_op<Streambuf, Handler>::
|
||||
stream<NextLayer>::read_op<DynamicBuffer, Handler>::
|
||||
operator()(error_code const& ec, bool again)
|
||||
{
|
||||
auto& d = *d_;
|
||||
@@ -117,9 +117,9 @@ operator()(error_code const& ec, bool again)
|
||||
// the handler is moved from the data block
|
||||
// before asio_handler_deallocate is called.
|
||||
d.ws.async_read_frame(
|
||||
d.fi, d.sb, std::move(*this));
|
||||
d.fi, d.db, std::move(*this));
|
||||
#else
|
||||
d.ws.async_read_frame(d.fi, d.sb, *this);
|
||||
d.ws.async_read_frame(d.fi, d.db, *this);
|
||||
#endif
|
||||
return;
|
||||
|
||||
|
||||
@@ -22,14 +22,13 @@
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/write.hpp>
|
||||
#include <beast/http/reason.hpp>
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/prepare_buffers.hpp>
|
||||
#include <beast/core/static_streambuf.hpp>
|
||||
#include <beast/core/stream_concepts.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <boost/endian/buffers.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@@ -94,10 +93,10 @@ stream_base::prepare_fh(close_code::value& code)
|
||||
}
|
||||
}
|
||||
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
stream_base::write_close(
|
||||
Streambuf& sb, close_reason const& cr)
|
||||
DynamicBuffer& db, close_reason const& cr)
|
||||
{
|
||||
using namespace boost::endian;
|
||||
frame_header fh;
|
||||
@@ -111,7 +110,7 @@ stream_base::write_close(
|
||||
fh.mask = role_ == detail::role_type::client;
|
||||
if(fh.mask)
|
||||
fh.key = maskgen_();
|
||||
detail::write(sb, fh);
|
||||
detail::write(db, fh);
|
||||
if(cr.code != close_code::none)
|
||||
{
|
||||
detail::prepared_key_type key;
|
||||
@@ -121,29 +120,29 @@ stream_base::write_close(
|
||||
std::uint8_t b[2];
|
||||
::new(&b[0]) big_uint16_buf_t{
|
||||
(std::uint16_t)cr.code};
|
||||
auto d = sb.prepare(2);
|
||||
auto d = db.prepare(2);
|
||||
boost::asio::buffer_copy(d,
|
||||
boost::asio::buffer(b));
|
||||
if(fh.mask)
|
||||
detail::mask_inplace(d, key);
|
||||
sb.commit(2);
|
||||
db.commit(2);
|
||||
}
|
||||
if(! cr.reason.empty())
|
||||
{
|
||||
auto d = sb.prepare(cr.reason.size());
|
||||
auto d = db.prepare(cr.reason.size());
|
||||
boost::asio::buffer_copy(d,
|
||||
boost::asio::const_buffer(
|
||||
cr.reason.data(), cr.reason.size()));
|
||||
if(fh.mask)
|
||||
detail::mask_inplace(d, key);
|
||||
sb.commit(cr.reason.size());
|
||||
db.commit(cr.reason.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
stream_base::write_ping(Streambuf& sb,
|
||||
stream_base::write_ping(DynamicBuffer& db,
|
||||
opcode op, ping_data const& data)
|
||||
{
|
||||
frame_header fh;
|
||||
@@ -156,19 +155,19 @@ stream_base::write_ping(Streambuf& sb,
|
||||
fh.mask = role_ == role_type::client;
|
||||
if(fh.mask)
|
||||
fh.key = maskgen_();
|
||||
detail::write(sb, fh);
|
||||
detail::write(db, fh);
|
||||
if(data.empty())
|
||||
return;
|
||||
detail::prepared_key_type key;
|
||||
if(fh.mask)
|
||||
detail::prepare_key(key, fh.key);
|
||||
auto d = sb.prepare(data.size());
|
||||
auto d = db.prepare(data.size());
|
||||
boost::asio::buffer_copy(d,
|
||||
boost::asio::const_buffers_1(
|
||||
data.data(), data.size()));
|
||||
if(fh.mask)
|
||||
detail::mask_inplace(d, key);
|
||||
sb.commit(data.size());
|
||||
db.commit(data.size());
|
||||
}
|
||||
|
||||
} // detail
|
||||
@@ -453,10 +452,10 @@ void
|
||||
stream<NextLayer>::
|
||||
ping(ping_data const& payload, error_code& ec)
|
||||
{
|
||||
detail::frame_streambuf sb;
|
||||
detail::frame_streambuf db;
|
||||
write_ping<static_streambuf>(
|
||||
sb, opcode::ping, payload);
|
||||
boost::asio::write(stream_, sb.data(), ec);
|
||||
db, opcode::ping, payload);
|
||||
boost::asio::write(stream_, db.data(), ec);
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
@@ -477,31 +476,35 @@ async_ping(ping_data const& payload, PingHandler&& handler)
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
read(opcode& op, Streambuf& streambuf)
|
||||
read(opcode& op, DynamicBuffer& dynabuf)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
error_code ec;
|
||||
read(op, streambuf, ec);
|
||||
read(op, dynabuf, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
read(opcode& op, Streambuf& streambuf, error_code& ec)
|
||||
read(opcode& op, DynamicBuffer& dynabuf, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
frame_info fi;
|
||||
for(;;)
|
||||
{
|
||||
read_frame(fi, streambuf, ec);
|
||||
read_frame(fi, dynabuf, ec);
|
||||
if(ec)
|
||||
break;
|
||||
op = fi.op;
|
||||
@@ -511,47 +514,51 @@ read(opcode& op, Streambuf& streambuf, error_code& ec)
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Streambuf, class ReadHandler>
|
||||
template<class DynamicBuffer, class ReadHandler>
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_read(opcode& op,
|
||||
Streambuf& streambuf, ReadHandler&& handler)
|
||||
DynamicBuffer& dynabuf, ReadHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
static_assert(beast::is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
beast::async_completion<
|
||||
ReadHandler, void(error_code)
|
||||
> completion(handler);
|
||||
read_op<Streambuf, decltype(completion.handler)>{
|
||||
completion.handler, *this, op, streambuf};
|
||||
read_op<DynamicBuffer, decltype(completion.handler)>{
|
||||
completion.handler, *this, op, dynabuf};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
read_frame(frame_info& fi, Streambuf& streambuf)
|
||||
read_frame(frame_info& fi, DynamicBuffer& dynabuf)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
error_code ec;
|
||||
read_frame(fi, streambuf, ec);
|
||||
read_frame(fi, dynabuf, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
close_code::value code{};
|
||||
for(;;)
|
||||
{
|
||||
@@ -630,7 +637,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
}
|
||||
}
|
||||
// read payload
|
||||
auto smb = streambuf.prepare(
|
||||
auto smb = dynabuf.prepare(
|
||||
detail::clamp(rd_need_));
|
||||
auto const bytes_transferred =
|
||||
stream_.read_some(smb, ec);
|
||||
@@ -652,7 +659,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
break;
|
||||
}
|
||||
}
|
||||
streambuf.commit(bytes_transferred);
|
||||
dynabuf.commit(bytes_transferred);
|
||||
fi.op = rd_opcode_;
|
||||
fi.fin = rd_fh_.fin && rd_need_ == 0;
|
||||
return;
|
||||
@@ -686,21 +693,21 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Streambuf, class ReadHandler>
|
||||
template<class DynamicBuffer, class ReadHandler>
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
stream<NextLayer>::
|
||||
async_read_frame(frame_info& fi,
|
||||
Streambuf& streambuf, ReadHandler&& handler)
|
||||
DynamicBuffer& dynabuf, ReadHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
static_assert(beast::is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
beast::async_completion<
|
||||
ReadHandler, void(error_code)> completion(handler);
|
||||
read_frame_op<Streambuf, decltype(completion.handler)>{
|
||||
completion.handler, *this, fi, streambuf};
|
||||
read_frame_op<DynamicBuffer, decltype(completion.handler)>{
|
||||
completion.handler, *this, fi, dynabuf};
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
@@ -712,6 +719,9 @@ write(ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(beast::is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
error_code ec;
|
||||
write(buffers, ec);
|
||||
if(ec)
|
||||
@@ -774,6 +784,9 @@ write_frame(bool fin, ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(beast::is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
error_code ec;
|
||||
write_frame(fin, buffers, ec);
|
||||
if(ec)
|
||||
@@ -951,8 +964,7 @@ build_response(http::request_v1<Body, Headers> const& req)
|
||||
return err("Missing Host");
|
||||
if(! req.headers.exists("Sec-WebSocket-Key"))
|
||||
return err("Missing Sec-WebSocket-Key");
|
||||
if(! rfc2616::token_in_list(
|
||||
req.headers["Upgrade"], "websocket"))
|
||||
if(! http::token_list{req.headers["Upgrade"]}.exists("websocket"))
|
||||
return err("Missing websocket Upgrade token");
|
||||
{
|
||||
auto const version =
|
||||
@@ -1005,8 +1017,7 @@ do_response(http::response_v1<Body, Headers> const& res,
|
||||
return fail();
|
||||
if(! is_upgrade(res))
|
||||
return fail();
|
||||
if(! rfc2616::ci_equal(
|
||||
res.headers["Upgrade"], "websocket"))
|
||||
if(! http::token_list{res.headers["Upgrade"]}.exists("websocket"))
|
||||
return fail();
|
||||
if(! res.headers.exists("Sec-WebSocket-Accept"))
|
||||
return fail();
|
||||
|
||||
@@ -120,7 +120,7 @@ decorate(Decorator&& d)
|
||||
This setting only affects the behavior of HTTP requests that
|
||||
implicitly or explicitly ask for a keepalive. For HTTP requests
|
||||
that indicate the connection should be closed, the connection is
|
||||
closed as per rfc2616.
|
||||
closed as per rfc7230.
|
||||
|
||||
The default setting is to close connections after a failed
|
||||
upgrade request.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <beast/websocket/detail/stream_base.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/core/streambuf_readstream.hpp>
|
||||
#include <beast/core/dynabuf_readstream.hpp>
|
||||
#include <beast/core/async_completion.hpp>
|
||||
#include <beast/core/detail/get_lowest_layer.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -78,7 +78,7 @@ struct frame_info
|
||||
@par Concepts
|
||||
@b `AsyncStream`,
|
||||
@b `Decorator`,
|
||||
@b `Streambuf`,
|
||||
@b `DynamicBuffer`,
|
||||
@b `SyncStream`
|
||||
*/
|
||||
template<class NextLayer>
|
||||
@@ -86,7 +86,7 @@ class stream : public detail::stream_base
|
||||
{
|
||||
friend class stream_test;
|
||||
|
||||
streambuf_readstream<NextLayer, streambuf> stream_;
|
||||
dynabuf_readstream<NextLayer, streambuf> stream_;
|
||||
|
||||
public:
|
||||
/// The type of the next layer.
|
||||
@@ -95,12 +95,12 @@ public:
|
||||
|
||||
/// The type of the lowest layer.
|
||||
using lowest_layer_type =
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
implementation_defined;
|
||||
#else
|
||||
#else
|
||||
typename beast::detail::get_lowest_layer<
|
||||
next_layer_type>::type;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Move-construct a stream.
|
||||
|
||||
@@ -404,12 +404,12 @@ public:
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class AcceptHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
AcceptHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_accept(AcceptHandler&& handler);
|
||||
|
||||
/** Read and respond to a WebSocket HTTP Upgrade request.
|
||||
@@ -530,12 +530,12 @@ public:
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class ConstBufferSequence, class AcceptHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
AcceptHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_accept(ConstBufferSequence const& buffers,
|
||||
AcceptHandler&& handler);
|
||||
|
||||
@@ -567,7 +567,7 @@ public:
|
||||
|
||||
@throws boost::system::system_error Thrown on failure.
|
||||
*/
|
||||
// VFALCO TODO This should also take a streambuf with any leftover bytes.
|
||||
// VFALCO TODO This should also take a DynamicBuffer with any leftover bytes.
|
||||
template<class Body, class Headers>
|
||||
void
|
||||
accept(http::request_v1<Body, Headers> const& request);
|
||||
@@ -647,12 +647,12 @@ public:
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class Body, class Headers, class AcceptHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
AcceptHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_accept(http::request_v1<Body, Headers> const& request,
|
||||
AcceptHandler&& handler);
|
||||
|
||||
@@ -784,12 +784,12 @@ public:
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class HandshakeHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
HandshakeHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_handshake(boost::string_ref const& host,
|
||||
boost::string_ref const& resource, HandshakeHandler&& h);
|
||||
|
||||
@@ -895,12 +895,12 @@ public:
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class CloseHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
CloseHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_close(close_reason const& cr, CloseHandler&& handler);
|
||||
|
||||
/** Send a WebSocket ping frame.
|
||||
@@ -973,12 +973,12 @@ public:
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class PingHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
PingHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_ping(ping_data const& payload, PingHandler&& handler);
|
||||
|
||||
/** Read a message from the stream.
|
||||
@@ -1007,14 +1007,14 @@ public:
|
||||
@param op A value to receive the message type.
|
||||
This object must remain valid until the handler is called.
|
||||
|
||||
@param streambuf A stream buffer to hold the message data.
|
||||
This object must remain valid until the handler is called.
|
||||
@param dynabuf A dynamic buffer to hold the message data after
|
||||
any masking or decompression has been applied.
|
||||
|
||||
@throws boost::system::system_error Thrown on failure.
|
||||
*/
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
read(opcode& op, Streambuf& streambuf);
|
||||
read(opcode& op, DynamicBuffer& dynabuf);
|
||||
|
||||
/** Read a message from the stream.
|
||||
|
||||
@@ -1042,15 +1042,14 @@ public:
|
||||
@param op A value to receive the message type.
|
||||
This object must remain valid until the handler is called.
|
||||
|
||||
@param streambuf A stream buffer to hold the message data.
|
||||
This object must remain valid until the handler is called.
|
||||
@param dynabuf A dynamic buffer to hold the message data after
|
||||
any masking or decompression has been applied.
|
||||
|
||||
@param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
read(opcode& op,
|
||||
Streambuf& streambuf, error_code& ec);
|
||||
read(opcode& op, DynamicBuffer& dynabuf, error_code& ec);
|
||||
|
||||
/** Start an asynchronous operation to read a message from the stream.
|
||||
|
||||
@@ -1086,8 +1085,9 @@ public:
|
||||
@param op A value to receive the message type.
|
||||
This object must remain valid until the handler is called.
|
||||
|
||||
@param streambuf A stream buffer to hold the message data.
|
||||
This object must remain valid until the handler is called.
|
||||
@param dynabuf A dynamic buffer to hold the message data after
|
||||
any masking or decompression has been applied. This object must
|
||||
remain valid until the handler is called.
|
||||
|
||||
@param handler The handler to be called when the read operation
|
||||
completes. Copies will be made of the handler as required. The
|
||||
@@ -1102,15 +1102,14 @@ public:
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class Streambuf, class ReadHandler>
|
||||
#if GENERATING_DOCS
|
||||
template<class DynamicBuffer, class ReadHandler>
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_read(opcode& op,
|
||||
Streambuf& streambuf, ReadHandler&& handler);
|
||||
#endif
|
||||
async_read(opcode& op, DynamicBuffer& dynabuf, ReadHandler&& handler);
|
||||
|
||||
/** Read a message frame from the stream.
|
||||
|
||||
@@ -1141,13 +1140,14 @@ public:
|
||||
|
||||
@param fi An object to store metadata about the message.
|
||||
|
||||
@param streambuf A stream buffer to hold the message data.
|
||||
@param dynabuf A dynamic buffer to hold the message data after
|
||||
any masking or decompression has been applied.
|
||||
|
||||
@throws boost::system::system_error Thrown on failure.
|
||||
*/
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
read_frame(frame_info& fi, Streambuf& streambuf);
|
||||
read_frame(frame_info& fi, DynamicBuffer& dynabuf);
|
||||
|
||||
/** Read a message frame from the stream.
|
||||
|
||||
@@ -1178,13 +1178,14 @@ public:
|
||||
|
||||
@param fi An object to store metadata about the message.
|
||||
|
||||
@param streambuf A stream buffer to hold the message data.
|
||||
@param dynabuf A dynamic buffer to hold the message data after
|
||||
any masking or decompression has been applied.
|
||||
|
||||
@param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
template<class Streambuf>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec);
|
||||
read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec);
|
||||
|
||||
/** Start an asynchronous operation to read a message frame from the stream.
|
||||
|
||||
@@ -1225,7 +1226,7 @@ public:
|
||||
@param fi An object to store metadata about the message.
|
||||
This object must remain valid until the handler is called.
|
||||
|
||||
@param streambuf A stream buffer to hold the message data after
|
||||
@param dynabuf A dynamic buffer to hold the message data after
|
||||
any masking or decompression has been applied. This object must
|
||||
remain valid until the handler is called.
|
||||
|
||||
@@ -1242,15 +1243,15 @@ public:
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using boost::asio::io_service::post().
|
||||
*/
|
||||
template<class Streambuf, class ReadHandler>
|
||||
#if GENERATING_DOCS
|
||||
template<class DynamicBuffer, class ReadHandler>
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_read_frame(frame_info& fi,
|
||||
Streambuf& streambuf, ReadHandler&& handler);
|
||||
DynamicBuffer& dynabuf, ReadHandler&& handler);
|
||||
|
||||
/** Write a message to the stream.
|
||||
|
||||
@@ -1369,12 +1370,12 @@ public:
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_write(ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler);
|
||||
|
||||
@@ -1478,12 +1479,12 @@ public:
|
||||
); @endcode
|
||||
*/
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
#if GENERATING_DOCS
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
#else
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
#endif
|
||||
async_write_frame(bool fin,
|
||||
ConstBufferSequence const& buffers, WriteHandler&& handler);
|
||||
|
||||
@@ -1495,8 +1496,8 @@ private:
|
||||
template<class Handler> class response_op;
|
||||
template<class Buffers, class Handler> class write_op;
|
||||
template<class Buffers, class Handler> class write_frame_op;
|
||||
template<class Streambuf, class Handler> class read_op;
|
||||
template<class Streambuf, class Handler> class read_frame_op;
|
||||
template<class DynamicBuffer, class Handler> class read_op;
|
||||
template<class DynamicBuffer, class Handler> class read_frame_op;
|
||||
|
||||
void
|
||||
reset();
|
||||
|
||||
39
src/beast/scripts/blacklist.supp
Normal file
39
src/beast/scripts/blacklist.supp
Normal file
@@ -0,0 +1,39 @@
|
||||
# Remember that this blacklist file is GLOBAL to all sanitizers
|
||||
# Be therefore extremely careful when considering to add a sanitizer
|
||||
# filter here instead of using a runtime suppression
|
||||
#
|
||||
# Remember also that filters here quite literally completely
|
||||
# remove instrumentation altogether, so filtering here means
|
||||
# that sanitizers such as tsan will false positive on problems
|
||||
# introduced by code filtered here.
|
||||
#
|
||||
# The main use for this file is ubsan, as it's the only sanitizer
|
||||
# without a runtime suppression facility.
|
||||
#
|
||||
# Be ESPECIALLY careful when filtering out entire source files!
|
||||
# Try if at all possible to filter only functions using fun:regex
|
||||
# Remember you must use mangled symbol names with fun:regex
|
||||
|
||||
|
||||
#### Compile time filters for ubsan ####
|
||||
|
||||
## The well known ubsan failure in libstdc++ extant for years :)
|
||||
# Line 96:24: runtime error: load of value 4294967221, which is not a valid value for type 'std::_Ios_Fmtflags'
|
||||
fun:*_Ios_Fmtflags*
|
||||
|
||||
# boost/any.hpp:259:16: runtime error: downcast of address 0x000004392e70 which does not point to an object of type 'any::holder<int>'
|
||||
fun:*any_cast*
|
||||
|
||||
# boost/lexical_cast.hpp:1625:43: runtime error: downcast of address 0x7fbb4fffbce8 which does not point to an object of type 'buffer_t' (aka 'parser_buf<std::basic_streambuf<char, char_traits<char> >, char>')
|
||||
fun:*shl_input_streamable*
|
||||
|
||||
|
||||
|
||||
|
||||
#### Compile time filters for asan ####
|
||||
|
||||
|
||||
#### Compile time filters for msan ####
|
||||
|
||||
|
||||
#### Compile time filters for tsan ####
|
||||
@@ -1,8 +1,11 @@
|
||||
#!/bin/bash -u
|
||||
# We use set -e and bash with -u to bail on first non zero exit code of any
|
||||
# processes launched or upon any unbound variable
|
||||
#!/usr/bin/env bash
|
||||
# We use set -e to bail on first non zero exit code of any processes launched
|
||||
# and -x to exit upon any unbound variable. -x will output command lines used
|
||||
# (with variable expansion)
|
||||
set -eux
|
||||
|
||||
# brew install bash (4) to get this working on OSX!
|
||||
shopt -s globstar
|
||||
set -ex
|
||||
|
||||
################################## ENVIRONMENT #################################
|
||||
|
||||
@@ -17,36 +20,90 @@ else
|
||||
export PATH=$VALGRIND_ROOT/bin:$LCOV_ROOT/usr/bin:$PATH
|
||||
fi
|
||||
|
||||
MAIN_BRANCH="0"
|
||||
# For builds not triggered by a pull request TRAVIS_BRANCH is the name of the
|
||||
# branch currently being built; whereas for builds triggered by a pull request
|
||||
# it is the name of the branch targeted by the pull request (in many cases this
|
||||
# will be master).
|
||||
if [[ $TRAVIS_BRANCH == "master" || $TRAVIS_BRANCH == "develop" ]]; then
|
||||
MAIN_BRANCH="1"
|
||||
fi
|
||||
|
||||
num_jobs="1"
|
||||
if [[ $(uname) == "Darwin" ]]; then
|
||||
num_jobs=$(sysctl -n hw.physicalcpu)
|
||||
elif [[ $(uname -s) == "Linux" ]]; then
|
||||
# CircleCI returns 32 phys procs, but 2 virt proc
|
||||
num_proc_units=$(nproc)
|
||||
# Physical cores
|
||||
num_jobs=$(lscpu -p | grep -v '^#' | sort -u -t, -k 2,4 | wc -l)
|
||||
if (("$num_proc_units" < "$num_jobs")); then
|
||||
num_jobs=$num_proc_units
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "using toolset: $CC"
|
||||
echo "using variant: $VARIANT"
|
||||
echo "using address-model: $ADDRESS_MODEL"
|
||||
echo "using PATH: $PATH"
|
||||
echo "using MAIN_BRANCH: $MAIN_BRANCH"
|
||||
echo "using BOOST_ROOT: $BOOST_ROOT"
|
||||
|
||||
#################################### HELPERS ###################################
|
||||
|
||||
function run_tests_with_gdb {
|
||||
for x in bin/**/*-tests; do scripts/run-with-gdb.sh "$x"; done
|
||||
function run_tests_with_debugger {
|
||||
for x in bin/**/$VARIANT/**/*-tests; do
|
||||
scripts/run-with-debugger.sh "$x"
|
||||
done
|
||||
}
|
||||
|
||||
function run_tests {
|
||||
for x in bin/**/*-tests; do "$x"; done
|
||||
for x in bin/**/$VARIANT/**/*-tests; do
|
||||
$x
|
||||
done
|
||||
}
|
||||
|
||||
num_procs=1
|
||||
if [[ $(uname) == "Darwin" ]]; then
|
||||
num_procs=$(sysctl -n hw.ncpu)
|
||||
elif [[ $(uname -s) == "Linux" ]]; then
|
||||
num_procs=$(lscpu -p | grep -v '^#' | sort -u -t, -k 2,4 | wc -l) # physical cores
|
||||
virt_num_procs=$(nproc) # CircleCI returns 32 phys procs, but 1 virt proc
|
||||
if (("$virt_num_procs" < "$num_procs")); then
|
||||
num_procs=$virt_num_procs
|
||||
function run_tests_with_valgrind {
|
||||
for x in bin/**/$VARIANT/**/*-tests; do
|
||||
if [[ $(basename $x) == "bench-tests" ]]; then
|
||||
$x
|
||||
else
|
||||
# TODO --max-stackframe=8388608
|
||||
# see: https://travis-ci.org/vinniefalco/Beast/jobs/132486245
|
||||
valgrind --error-exitcode=1 "$x"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function build_beast {
|
||||
$BOOST_ROOT/bjam toolset=$CC \
|
||||
variant=$VARIANT \
|
||||
address-model=$ADDRESS_MODEL -j${num_procs}
|
||||
address-model=$ADDRESS_MODEL \
|
||||
-j${num_jobs}
|
||||
}
|
||||
|
||||
function run_autobahn_test_suite {
|
||||
# Run autobahn tests
|
||||
wsecho=$(find bin -name "websocket-echo" | grep /$VARIANT/)
|
||||
nohup $wsecho&
|
||||
|
||||
# We need to wait a while so wstest can connect!
|
||||
sleep 5
|
||||
cd scripts && wstest -m fuzzingclient
|
||||
cd ..
|
||||
# Show the output
|
||||
cat nohup.out
|
||||
rm nohup.out
|
||||
# Show what jobs are running
|
||||
jobs
|
||||
# Wait a while for things to wind down before issuing a kill
|
||||
sleep 5
|
||||
# Kill it gracefully
|
||||
kill -INT %1
|
||||
# Wait for all the jobs to finish
|
||||
wait
|
||||
# Parse the test results, with python>=2.5<3 script
|
||||
python scripts/parseautobahn.py scripts/autoresults/index.json
|
||||
}
|
||||
|
||||
##################################### BUILD ####################################
|
||||
@@ -62,24 +119,12 @@ if [[ $VARIANT == "coverage" ]]; then
|
||||
lcov --no-external -c -i -d . -o baseline.info > /dev/null
|
||||
|
||||
# Perform test
|
||||
if [[ $MAIN_BRANCH == "1" ]]; then
|
||||
run_tests_with_valgrind
|
||||
run_autobahn_test_suite
|
||||
else
|
||||
run_tests
|
||||
|
||||
# Run autobahn tests
|
||||
export SERVER=$(find . -name "websocket-echo")
|
||||
nohup $SERVER&
|
||||
|
||||
# We need to wait a while so wstest can connect!
|
||||
sleep 5
|
||||
cd scripts && wstest -m fuzzingclient
|
||||
cd ..
|
||||
# Show the output
|
||||
cat nohup.out
|
||||
rm nohup.out
|
||||
jobs
|
||||
sleep 5
|
||||
# Kill it gracefully
|
||||
kill -INT %1
|
||||
wait
|
||||
fi
|
||||
|
||||
# Create test coverage data file
|
||||
lcov --no-external -c -d . -o testrun.info > /dev/null
|
||||
@@ -88,20 +133,13 @@ if [[ $VARIANT == "coverage" ]]; then
|
||||
lcov -a baseline.info -a testrun.info -o lcov-all.info > /dev/null
|
||||
|
||||
# Extract only include/beast, and don\'t report on examples/test
|
||||
lcov -e "lcov-all.info" "*/include/beast/*" -o lcov.info > /dev/null
|
||||
lcov -e "lcov-all.info" "$PWD/include/beast/*" -o lcov.info > /dev/null
|
||||
|
||||
~/.local/bin/codecov -X gcov
|
||||
else
|
||||
# TODO: make a function
|
||||
run_tests_with_gdb
|
||||
cat lcov.info | node_modules/.bin/coveralls
|
||||
|
||||
if [[ $VARIANT == "debug" ]]; then
|
||||
for x in bin/**/*-tests; do
|
||||
# if [[ $x != "bench-tests" ]]; then
|
||||
valgrind --error-exitcode=1 "$x"
|
||||
## declare -i RESULT=$RESULT + $?
|
||||
# fi
|
||||
done
|
||||
echo
|
||||
fi
|
||||
# Clean up these stragglers so BOOST_ROOT cache is clean
|
||||
find $BOOST_ROOT/bin.v2 -name "*.gcda" | xargs rm -f
|
||||
else
|
||||
run_tests_with_debugger
|
||||
fi
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash -u
|
||||
#!/usr/bin/env bash
|
||||
# Assumptions:
|
||||
# 1) BOOST_ROOT and BOOST_URL are already defined,
|
||||
# and contain valid values.
|
||||
@@ -6,7 +6,7 @@
|
||||
# folder name internal to boost's .tar.gz
|
||||
# When testing you can force a boost build by clearing travis caches:
|
||||
# https://travis-ci.org/ripple/rippled/caches
|
||||
set -e
|
||||
set -eu
|
||||
if [ ! -d "$BOOST_ROOT/lib" ]
|
||||
then
|
||||
wget $BOOST_URL -O /tmp/boost.tar.gz
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#!/bin/bash -u
|
||||
#!/usr/bin/env bash
|
||||
# Exit if anything fails.
|
||||
set -e
|
||||
set -eux
|
||||
|
||||
HERE=$PWD
|
||||
|
||||
# Override gcc version to $GCC_VER.
|
||||
# Put an appropriate symlink at the front of the path.
|
||||
mkdir -v $HOME/bin
|
||||
@@ -44,3 +47,8 @@ tar xfvz lcov-1.12.tar.gz -C $HOME
|
||||
# Set install path
|
||||
mkdir -p $LCOV_ROOT
|
||||
cd $HOME/lcov-1.12 && make install PREFIX=$LCOV_ROOT
|
||||
|
||||
# Install coveralls reporter
|
||||
cd $HERE
|
||||
mkdir -p node_modules
|
||||
npm install coveralls
|
||||
|
||||
4
src/beast/scripts/install-valgrind.sh
Normal file → Executable file
4
src/beast/scripts/install-valgrind.sh
Normal file → Executable file
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash -u
|
||||
#!/usr/bin/env bash
|
||||
# Assumptions:
|
||||
# 1) VALGRIND_ROOT is already defined, and contains a valid values
|
||||
set -e
|
||||
set -eu
|
||||
if [ ! -d "$VALGRIND_ROOT/bin" ]
|
||||
then
|
||||
# These are specified in the addons/apt section of .travis.yml
|
||||
|
||||
43
src/beast/scripts/parseautobahn.py
Normal file
43
src/beast/scripts/parseautobahn.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
|
||||
VARIANT = os.environ.get('VARIANT', 'release')
|
||||
EXPECTED_BEHAVIOR = ('OK', 'UNIMPLEMENTED', 'INFORMATIONAL')
|
||||
EXPECTED_BEHAVIOR_CLOSE = ('OK', 'INFORMATIONAL')
|
||||
WARNINGS = ("peer did not respond (in time) in closing handshake", )
|
||||
|
||||
args = sys.argv[1:]
|
||||
fn = os.path.abspath(args[0])
|
||||
indexPath = os.path.dirname(fn)
|
||||
relativeToIndex = lambda f: os.path.join(indexPath, f)
|
||||
print "index", fn
|
||||
|
||||
|
||||
failures = []
|
||||
warnings = []
|
||||
|
||||
with open(fn, 'r') as fh:
|
||||
index = json.load(fh)
|
||||
for servername, serverResults in index.items():
|
||||
for test in serverResults:
|
||||
result = serverResults[test]
|
||||
if ((result['behavior'] not in EXPECTED_BEHAVIOR) or
|
||||
result['behaviorClose'] not in EXPECTED_BEHAVIOR_CLOSE):
|
||||
with open(relativeToIndex(result['reportfile'])) as rh:
|
||||
report = json.load(rh)
|
||||
if (report.get('wasNotCleanReason', '') in WARNINGS and
|
||||
VARIANT != 'release'):
|
||||
warnings.append(report)
|
||||
else:
|
||||
failures.append(report)
|
||||
|
||||
|
||||
if warnings:
|
||||
print >> sys.stderr, json.dumps(warnings, indent=2)
|
||||
print >> sys.stderr, 'there was %s warnings' % len(warnings)
|
||||
|
||||
if failures:
|
||||
print >> sys.stderr, json.dumps(failures, indent=2)
|
||||
print >> sys.stderr, 'there was %s failures' % len(failures)
|
||||
sys.exit(1)
|
||||
22
src/beast/scripts/run-with-debugger.sh
Executable file
22
src/beast/scripts/run-with-debugger.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
if [[ $(uname) == "Darwin" ]]; then
|
||||
# -o runs after loading the binary
|
||||
# -k runs after any crash
|
||||
# We use a ghetto appromixation of --return-child-result, exiting with
|
||||
# 1 on a crash
|
||||
lldb --batch \
|
||||
-o 'run' \
|
||||
-k 'thread backtrace all' \
|
||||
-k 'script import os; os._exit(1)' \
|
||||
$@
|
||||
else
|
||||
gdb --silent \
|
||||
--batch \
|
||||
--return-child-result \
|
||||
-ex="set print thread-events off" \
|
||||
-ex=run \
|
||||
-ex="thread apply all bt full" \
|
||||
--args $@
|
||||
fi
|
||||
@@ -21,6 +21,7 @@ unit-test core-tests :
|
||||
core/buffer_concepts.cpp
|
||||
core/buffers_adapter.cpp
|
||||
core/consuming_buffers.cpp
|
||||
core/dynabuf_readstream.cpp
|
||||
core/error.cpp
|
||||
core/handler_alloc.cpp
|
||||
core/handler_concepts.cpp
|
||||
@@ -30,9 +31,8 @@ unit-test core-tests :
|
||||
core/static_string.cpp
|
||||
core/stream_concepts.cpp
|
||||
core/streambuf.cpp
|
||||
core/streambuf_readstream.cpp
|
||||
core/to_string.cpp
|
||||
core/write_streambuf.cpp
|
||||
core/write_dynabuf.cpp
|
||||
core/detail/base64.cpp
|
||||
core/detail/empty_base_optimization.cpp
|
||||
core/detail/get_lowest_layer.cpp
|
||||
@@ -41,6 +41,7 @@ unit-test core-tests :
|
||||
|
||||
unit-test http-tests :
|
||||
../extras/beast/unit_test/main.cpp
|
||||
http/basic_dynabuf_body.cpp
|
||||
http/basic_headers.cpp
|
||||
http/basic_parser_v1.cpp
|
||||
http/body_type.cpp
|
||||
@@ -54,7 +55,6 @@ unit-test http-tests :
|
||||
http/read.cpp
|
||||
http/reason.cpp
|
||||
http/resume_context.cpp
|
||||
http/rfc2616.cpp
|
||||
http/rfc7230.cpp
|
||||
http/status.cpp
|
||||
http/streambuf_body.cpp
|
||||
|
||||
@@ -15,6 +15,7 @@ add_executable (core-tests
|
||||
buffer_concepts.cpp
|
||||
buffers_adapter.cpp
|
||||
consuming_buffers.cpp
|
||||
dynabuf_readstream.cpp
|
||||
error.cpp
|
||||
handler_alloc.cpp
|
||||
handler_concepts.cpp
|
||||
@@ -24,9 +25,8 @@ add_executable (core-tests
|
||||
static_string.cpp
|
||||
stream_concepts.cpp
|
||||
streambuf.cpp
|
||||
streambuf_readstream.cpp
|
||||
to_string.cpp
|
||||
write_streambuf.cpp
|
||||
write_dynabuf.cpp
|
||||
detail/base64.cpp
|
||||
detail/empty_base_optimization.cpp
|
||||
detail/get_lowest_layer.cpp
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/core/streambuf_readstream.hpp>
|
||||
#include <beast/core/dynabuf_readstream.hpp>
|
||||
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/test/fail_stream.hpp>
|
||||
@@ -17,11 +17,11 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
class streambuf_readstream_test
|
||||
class dynabuf_readstream_test
|
||||
: public unit_test::suite
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
using self = streambuf_readstream_test;
|
||||
using self = dynabuf_readstream_test;
|
||||
|
||||
public:
|
||||
void testSpecialMembers()
|
||||
@@ -29,16 +29,16 @@ public:
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
boost::asio::io_service ios;
|
||||
{
|
||||
streambuf_readstream<socket_type, streambuf> srs(ios);
|
||||
streambuf_readstream<socket_type, streambuf> srs2(std::move(srs));
|
||||
dynabuf_readstream<socket_type, streambuf> srs(ios);
|
||||
dynabuf_readstream<socket_type, streambuf> srs2(std::move(srs));
|
||||
srs = std::move(srs2);
|
||||
expect(&srs.get_io_service() == &ios);
|
||||
expect(&srs.get_io_service() == &srs2.get_io_service());
|
||||
}
|
||||
{
|
||||
socket_type sock(ios);
|
||||
streambuf_readstream<socket_type&, streambuf> srs(sock);
|
||||
streambuf_readstream<socket_type&, streambuf> srs2(std::move(srs));
|
||||
dynabuf_readstream<socket_type&, streambuf> srs(sock);
|
||||
dynabuf_readstream<socket_type&, streambuf> srs2(std::move(srs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
{
|
||||
test::fail_stream<
|
||||
test::string_stream> fs(n, ios_, ", world!");
|
||||
streambuf_readstream<
|
||||
dynabuf_readstream<
|
||||
decltype(fs)&, streambuf> srs(fs);
|
||||
srs.buffer().commit(buffer_copy(
|
||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
{
|
||||
test::fail_stream<
|
||||
test::string_stream> fs(n, ios_, ", world!");
|
||||
streambuf_readstream<
|
||||
dynabuf_readstream<
|
||||
decltype(fs)&, streambuf> srs(fs);
|
||||
srs.capacity(3);
|
||||
srs.buffer().commit(buffer_copy(
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
{
|
||||
test::fail_stream<
|
||||
test::string_stream> fs(n, ios_, ", world!");
|
||||
streambuf_readstream<
|
||||
dynabuf_readstream<
|
||||
decltype(fs)&, streambuf> srs(fs);
|
||||
srs.buffer().commit(buffer_copy(
|
||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
{
|
||||
test::fail_stream<
|
||||
test::string_stream> fs(n, ios_, ", world!");
|
||||
streambuf_readstream<
|
||||
dynabuf_readstream<
|
||||
decltype(fs)&, streambuf> srs(fs);
|
||||
srs.capacity(3);
|
||||
srs.buffer().commit(buffer_copy(
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(streambuf_readstream,core,beast);
|
||||
BEAST_DEFINE_TESTSUITE(dynabuf_readstream,core,beast);
|
||||
|
||||
} // beast
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/core/write_streambuf.hpp>
|
||||
#include <beast/core/write_dynabuf.hpp>
|
||||
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class write_streambuf_test : public beast::unit_test::suite
|
||||
class write_dynabuf_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void run() override
|
||||
@@ -31,6 +31,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(write_streambuf,core,beast);
|
||||
BEAST_DEFINE_TESTSUITE(write_dynabuf,core,beast);
|
||||
|
||||
} // beast
|
||||
@@ -6,7 +6,10 @@ GroupSources(test/http "/")
|
||||
|
||||
add_executable (http-tests
|
||||
${BEAST_INCLUDES}
|
||||
message_fuzz.hpp
|
||||
fail_parser.hpp
|
||||
../../extras/beast/unit_test/main.cpp
|
||||
basic_dynabuf_body.cpp
|
||||
basic_headers.cpp
|
||||
basic_parser_v1.cpp
|
||||
body_type.cpp
|
||||
@@ -20,7 +23,6 @@ add_executable (http-tests
|
||||
read.cpp
|
||||
reason.cpp
|
||||
resume_context.cpp
|
||||
rfc2616.cpp
|
||||
rfc7230.cpp
|
||||
status.cpp
|
||||
streambuf_body.cpp
|
||||
@@ -35,6 +37,7 @@ endif()
|
||||
|
||||
add_executable (bench-tests
|
||||
${BEAST_INCLUDES}
|
||||
nodejs_parser.hpp
|
||||
../../extras/beast/unit_test/main.cpp
|
||||
nodejs_parser.cpp
|
||||
parser_bench.cpp
|
||||
|
||||
9
src/beast/test/http/basic_dynabuf_body.cpp
Normal file
9
src/beast/test/http/basic_dynabuf_body.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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>
|
||||
File diff suppressed because it is too large
Load Diff
112
src/beast/test/http/fail_parser.hpp
Normal file
112
src/beast/test/http/fail_parser.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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;
|
||||
int body_rv_ = 0;
|
||||
|
||||
public:
|
||||
std::string body;
|
||||
|
||||
template<class... Args>
|
||||
explicit
|
||||
fail_parser(test::fail_counter& fc, Args&&... args)
|
||||
: fc_(fc)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_body_rv(int 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);
|
||||
}
|
||||
|
||||
int on_headers(std::uint64_t content_length, error_code& ec)
|
||||
{
|
||||
if(fc_.fail(ec))
|
||||
return 0;
|
||||
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,6 +9,7 @@
|
||||
#include <beast/http/message.hpp>
|
||||
|
||||
#include <beast/http/headers.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -126,9 +127,30 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void testSwap()
|
||||
{
|
||||
message<true, string_body, headers> m1;
|
||||
message<true, string_body, headers> m2;
|
||||
m1.url = "u";
|
||||
m1.body = "1";
|
||||
m1.headers.insert("h", "v");
|
||||
m2.method = "G";
|
||||
m2.body = "2";
|
||||
swap(m1, m2);
|
||||
expect(m1.method == "G");
|
||||
expect(m2.method.empty());
|
||||
expect(m1.url.empty());
|
||||
expect(m2.url == "u");
|
||||
expect(m1.body == "2");
|
||||
expect(m2.body == "1");
|
||||
expect(! m1.headers.exists("h"));
|
||||
expect(m2.headers.exists("h"));
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
testConstruction();
|
||||
testSwap();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
|
||||
#define BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
|
||||
|
||||
#include <beast/core/write_streambuf.hpp>
|
||||
#include <beast/core/write_dynabuf.hpp>
|
||||
#include <beast/http/detail/basic_parser_v1.hpp>
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/http/message_v1.hpp>
|
||||
|
||||
#include <beast/http/headers.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
|
||||
@@ -78,10 +80,36 @@ public:
|
||||
expect(! is_keep_alive(m));
|
||||
}
|
||||
|
||||
void testSwap()
|
||||
{
|
||||
message_v1<false, string_body, headers> m1;
|
||||
message_v1<false, string_body, headers> m2;
|
||||
m1.status = 200;
|
||||
m1.version = 10;
|
||||
m1.body = "1";
|
||||
m1.headers.insert("h", "v");
|
||||
m2.status = 404;
|
||||
m2.reason = "OK";
|
||||
m2.body = "2";
|
||||
m2.version = 11;
|
||||
swap(m1, m2);
|
||||
expect(m1.status == 404);
|
||||
expect(m2.status == 200);
|
||||
expect(m1.reason == "OK");
|
||||
expect(m2.reason.empty());
|
||||
expect(m1.version == 11);
|
||||
expect(m2.version == 10);
|
||||
expect(m1.body == "2");
|
||||
expect(m2.body == "1");
|
||||
expect(! m1.headers.exists("h"));
|
||||
expect(m2.headers.exists("h"));
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
testFreeFunctions();
|
||||
testPrepare();
|
||||
testSwap();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "nodejs-parser/http_parser.h"
|
||||
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
@@ -611,7 +611,7 @@ nodejs_basic_parser<Derived>::check_header()
|
||||
{
|
||||
if (! value_.empty())
|
||||
{
|
||||
rfc2616::trim_right_in_place(value_);
|
||||
//detail::trim(value_);
|
||||
call_on_field(field_, value_,
|
||||
has_on_field<Derived>{});
|
||||
field_.clear();
|
||||
|
||||
@@ -38,8 +38,8 @@ public:
|
||||
check("http", parse_error::bad_version);
|
||||
check("http", parse_error::bad_crlf);
|
||||
check("http", parse_error::bad_request);
|
||||
check("http", parse_error::bad_status_code);
|
||||
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);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/http/read.hpp>
|
||||
|
||||
#include "fail_parser.hpp"
|
||||
|
||||
#include <beast/http/headers.hpp>
|
||||
#include <beast/http/streambuf_body.hpp>
|
||||
#include <beast/test/fail_stream.hpp>
|
||||
@@ -24,77 +26,6 @@ class read_test
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
public:
|
||||
template<bool isRequest>
|
||||
class fail_parser
|
||||
: public basic_parser_v1<isRequest, fail_parser<isRequest>>
|
||||
{
|
||||
test::fail_counter& fc_;
|
||||
|
||||
public:
|
||||
template<class... Args>
|
||||
explicit
|
||||
fail_parser(test::fail_counter& fc, Args&&... args)
|
||||
: fc_(fc)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int on_headers(error_code& ec)
|
||||
{
|
||||
fc_.fail(ec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void on_body(boost::string_ref const&, error_code& ec)
|
||||
{
|
||||
fc_.fail(ec);
|
||||
}
|
||||
|
||||
void on_complete(error_code& ec)
|
||||
{
|
||||
fc_.fail(ec);
|
||||
}
|
||||
};
|
||||
|
||||
template<bool isRequest>
|
||||
void failMatrix(const char* s, yield_context do_yield)
|
||||
{
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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/rfc2616.hpp>
|
||||
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
namespace rfc2616 {
|
||||
namespace test {
|
||||
|
||||
class rfc2616_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
checkSplit(std::string const& s,
|
||||
std::vector <std::string> const& expected)
|
||||
{
|
||||
auto const parsed = split_commas(s.begin(), s.end());
|
||||
expect (parsed == expected);
|
||||
}
|
||||
|
||||
void testSplit()
|
||||
{
|
||||
checkSplit("", {});
|
||||
checkSplit(" ", {});
|
||||
checkSplit(" ", {});
|
||||
checkSplit("\t", {});
|
||||
checkSplit(" \t ", {});
|
||||
checkSplit(",", {});
|
||||
checkSplit(",,", {});
|
||||
checkSplit(" ,", {});
|
||||
checkSplit(" , ,", {});
|
||||
checkSplit("x", {"x"});
|
||||
checkSplit(" x", {"x"});
|
||||
checkSplit(" \t x", {"x"});
|
||||
checkSplit("x ", {"x"});
|
||||
checkSplit("x \t", {"x"});
|
||||
checkSplit(" \t x \t ", {"x"});
|
||||
checkSplit("\"\"", {});
|
||||
checkSplit(" \"\"", {});
|
||||
checkSplit("\"\" ", {});
|
||||
checkSplit("\"x\"", {"x"});
|
||||
checkSplit("\" \"", {" "});
|
||||
checkSplit("\" x\"", {" x"});
|
||||
checkSplit("\"x \"", {"x "});
|
||||
checkSplit("\" x \"", {" x "});
|
||||
checkSplit("\"\tx \"", {"\tx "});
|
||||
checkSplit("x,y", {"x", "y"});
|
||||
checkSplit("x ,\ty ", {"x", "y"});
|
||||
checkSplit("x, y, z", {"x","y","z"});
|
||||
checkSplit("x, \"y\", z", {"x","y","z"});
|
||||
checkSplit(",,x,,\"y\",,", {"x","y"});
|
||||
}
|
||||
|
||||
void
|
||||
checkIter(std::string const& s,
|
||||
std::vector<std::string> const& expected)
|
||||
{
|
||||
std::vector<std::string> got;
|
||||
for(auto const& v : make_list(s))
|
||||
got.emplace_back(v);
|
||||
expect(got == expected);
|
||||
}
|
||||
|
||||
void
|
||||
testIter()
|
||||
{
|
||||
checkIter("x", {"x"});
|
||||
checkIter(" x", {"x"});
|
||||
checkIter("x\t", {"x"});
|
||||
checkIter("\tx ", {"x"});
|
||||
checkIter(",x", {"x"});
|
||||
checkIter("x,", {"x"});
|
||||
checkIter(",x,", {"x"});
|
||||
checkIter(" , x\t,\t", {"x"});
|
||||
checkIter("x,y", {"x", "y"});
|
||||
checkIter("x, ,y ", {"x", "y"});
|
||||
checkIter("\"x\"", {"x"});
|
||||
}
|
||||
|
||||
void
|
||||
testList()
|
||||
{
|
||||
expect(token_in_list("x", "x"));
|
||||
expect(token_in_list("x,y", "x"));
|
||||
expect(token_in_list("x,y", "y"));
|
||||
expect(token_in_list("x, y ", "y"));
|
||||
expect(token_in_list("x", "X"));
|
||||
expect(token_in_list("Y", "y"));
|
||||
expect(token_in_list("close, keepalive", "close"));
|
||||
expect(token_in_list("close, keepalive", "keepalive"));
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
testSplit();
|
||||
testIter();
|
||||
testList();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(rfc2616,http,beast);
|
||||
|
||||
} // test
|
||||
} // rfc2616
|
||||
} // beast
|
||||
@@ -7,3 +7,240 @@
|
||||
|
||||
// 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));
|
||||
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});
|
||||
expect(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);
|
||||
expect(got == good, fmt(got));
|
||||
};
|
||||
auto const cq =
|
||||
[&](std::string const& s, std::string const& good)
|
||||
{
|
||||
auto const got = str(param_list{s});
|
||||
expect(got == good, fmt(got));
|
||||
};
|
||||
|
||||
ce("");
|
||||
cs(" ;\t i =\t 1 \t", ";i=1");
|
||||
cq("\t; \t xyz=1 ; ijk=\"q\\\"t\"", ";xyz=1;ijk=q\"t");
|
||||
|
||||
// invalid strings
|
||||
cs(";", "");
|
||||
cs(";,", "");
|
||||
cs(";xy", "");
|
||||
cs(";xy", "");
|
||||
cs(";xy ", "");
|
||||
cs(";xy,", "");
|
||||
|
||||
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});
|
||||
expect(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);
|
||||
expect(got == good, fmt(got));
|
||||
};
|
||||
auto const cq =
|
||||
[&](std::string const& s, std::string const& good)
|
||||
{
|
||||
auto const got = str(ext_list{s});
|
||||
expect(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 )
|
||||
*/
|
||||
ce("");
|
||||
cs(",", "");
|
||||
cs(", ", "");
|
||||
cs(",\t", "");
|
||||
cs(", \t", "");
|
||||
cs(" ", "");
|
||||
cs(" ,", "");
|
||||
cs("\t,", "");
|
||||
cs("\t , \t", "");
|
||||
cs(",,", "");
|
||||
cs(" , \t,, \t,", "");
|
||||
|
||||
ce("a");
|
||||
ce("ab");
|
||||
ce("a,b");
|
||||
cs(" a ", "a");
|
||||
cs("\t a, b\t , c\t", "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=\"");
|
||||
|
||||
expect(ext_list{"a,b;i=1,c;j=2;k=3"}.exists("A"));
|
||||
expect(ext_list{"a,b;i=1,c;j=2;k=3"}.exists("b"));
|
||||
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});
|
||||
expect(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);
|
||||
expect(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");
|
||||
|
||||
expect(token_list{"a,b,c"}.exists("A"));
|
||||
expect(token_list{"a,b,c"}.exists("b"));
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user