diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c2921d..25550a86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Version 83: * Add buffer_front * Add wstest compression option * Turn some flat_static_buffer_tests on +* Documentation work WebSocket diff --git a/doc/qbk/04_http.qbk b/doc/qbk/04_http.qbk index 212f090d..c7ffa17b 100644 --- a/doc/qbk/04_http.qbk +++ b/doc/qbk/04_http.qbk @@ -69,6 +69,124 @@ format using __Asio__. Specifically, the library provides: ] ] +Interfaces for operating on HTTP messages are structured into several +layers. The highest level provides ease of use, while lower levels provide +progressively more control, options, and flexibility. At the lowest level +customization points are provided, where user defined types can replace +parts of the implementation. The layers are arranged thusly: + +[table +[[Level][Read/Write What][Description]] +[ + [[*6]] + [ + __message__ + ][ + At the highest level, these free functions send or receive + a complete HTTP message in one call. They are designed for + ease of use: + [link beast.ref.beast__http__read.overload4 `read`], + [link beast.ref.beast__http__write.overload4 `write`], + [link beast.ref.beast__http__async_read.overload2 `async_read`], and + [link beast.ref.beast__http__async_write.overload2 `async_write`]. + ] +][ + [[*5]] + [ + __parser__, __serializer__ + ][ + For more control, callers may take responsibility for managing the + required __parser__ or __serializer__ transient state objects. + This allows additional configuration such as limiting the number + of bytes for message components during parsing, or regulating the + size of buffers emitted during output. These functions send or + receive complete messages using a serializer or parser: + [link beast.ref.beast__http__read.overload2 `read`], + [link beast.ref.beast__http__write.overload2 `write`], + [link beast.ref.beast__http__async_read.overload1 `async_read`], and + [link beast.ref.beast__http__async_write.overload1 `async_write`]. + + ] +][ + [[*4]] + [ + __header__ + ][ + Sometimes it is necessary to first send or receive the HTTP + header. For example, to read the header and take action before + continuing to read the body. These functions use a __parser__ + or __serializer__ to read or write the header: + [link beast.ref.beast__http__read_header.overload2 `read_header`], + [link beast.ref.beast__http__write_header.overload2 `write_header`], + [link beast.ref.beast__http__async_read_header `async_read_header`], and + [link beast.ref.beast__http__async_write_header `async_write_header`]. + ] +][ + [[*3]] + [ + partial __message__ + ][ + All of the stream operations at higher levels thus far have operated + on a complete header or message. At this level it is possible to + send and receive messages incrementally. This allows resource + constrained implementations to perform work bounded on storage, + or allows better control when setting timeouts for example. + These functions read or write bounded amounts of data and return + the number of bytes transacted: + [link beast.ref.beast__http__read_some.overload2 `read_some`], + [link beast.ref.beast__http__write_some.overload2 `write_some`], + [link beast.ref.beast__http__async_read_some `async_read_some`], and + [link beast.ref.beast__http__async_write_some `async_write_some`]. + ] +][ + [[*2]] + [ + [@https://tools.ietf.org/html/rfc7230#section-4.1 ['chunked-body]] + ][ + Until now parse and serialize operations apply or remove the chunked + transfer coding as needed for message payloads whose size is not known + ahead of time. For some domain specific niches, it is necessary + to assume direct control over incoming or outgoing chunks in a chunk + encoded message payload. + For parsing this is achieved by setting hooks using the functions + [link beast.ref.beast__http__parser.on_chunk_header `on_chunk_header`] and/or + [link beast.ref.beast__http__parser.on_chunk_body `on_chunk_body`]. + For serializing callers may first emit the header, and then use + these buffer sequence adapters to control the contents of each chunk + including + [@https://tools.ietf.org/html/rfc7230#section-4.1.1 ['chunk extensions]] + and the + [@https://tools.ietf.org/html/rfc7230#section-4.1.2 ['trailer-part]]: + [link beast.ref.beast__http__chunk_body `chunk_body`], + [link beast.ref.beast__http__chunk_crlf `chunk_crlf`], + [link beast.ref.beast__http__chunk_header `chunk_header`], and + [link beast.ref.beast__http__chunk_last `chunk_last`]. + ] +][ + [[*1]] + [ + buffers + ][ + For ultimate control, the use of library stream algorithms may + be bypassed entirely and instead work directly with buffers by + calling members of __parser__ or __serializer__. + ] +][ + [[*0]] + [ + ['user-defined] + ][ + In addition to the typical customization points of __Stream__ + and __DynamicBuffer__, user-defined types may replace parts of + the library implementation at the lowest level. The customization + points include __Fields__ for creating a container to store HTTP + fields, __Body__ for defining containers and algorithms used for + HTTP message payloads, and user-defined subclasses of + __basic_parser__ for implementing custom message representation + strategies. + ] +]] + [note This documentation assumes some familiarity with __Asio__ and the HTTP protocol specification described in __rfc7230__. Sample diff --git a/doc/qbk/07_concepts/Body.qbk b/doc/qbk/07_concepts/Body.qbk index 5421286a..44d669aa 100644 --- a/doc/qbk/07_concepts/Body.qbk +++ b/doc/qbk/07_concepts/Body.qbk @@ -11,17 +11,24 @@ A [*Body] type is supplied as a template argument to the __message__ class. It controls both the type of the data member of the resulting message object, and the algorithms used during parsing and serialization. +[heading Associated Types] + +* [link beast.ref.beast__http__is_body `is_body`] +* __BodyReader__ +* __BodyWriter__ + +[heading Requirements] + In this table: -* `X` is a type meeting the requirements of [*Body]. - -* `m` is a value of type `message` where `b` is a `bool` value +* `B` is a type meeting the requirements of [*Body]. +* `m` is a value of type `message` where `b` is a `bool` value and `F` is a type meeting the requirements of [*Fields]. -[table Body requirements -[[expression] [type] [semantics, pre/post-conditions]] +[table Valid expressions +[[Expression] [Type] [Semantics, Pre/Post-conditions]] [ - [`X::value_type`] + [`B::value_type`] [] [ The type of the `message::body` member. @@ -29,7 +36,7 @@ In this table: will be not movable or not copyable. ] ][ - [`X::writer`] + [`B::writer`] [] [ If present, indicates that the body can hold a message body @@ -39,7 +46,7 @@ In this table: are placed. ] ][ - [`X::reader`] + [`B::reader`] [] [ If present, indicates that the body is serializable. The type @@ -48,11 +55,16 @@ In this table: the message body for serialization. ] ][ - [`X::size(X::value_type v)`] + [ + ``` + B::size( + B::value_type body) + ``` + ] [`std::uint64_t`] [ This static member function is optional. It returns the payload - size of `v` not including any chunked transfer encoding. The + size of `body` not including any chunked transfer encoding. The function shall not exit via an exception. When this function is present: @@ -80,15 +92,7 @@ In this table: will erase the Content-Length field, and add "chunked" as the last encoding in the Transfer-Encoding field if it is not already present. ] -][ - [`is_body`] - [`std::true_type`] - [ - An alias for `std::true_type` for `X`, otherwise an alias - for `std::false_type`. - ] -] -] +]] [heading Exemplar] @@ -97,9 +101,11 @@ In this table: [heading Models] * [link beast.ref.beast__http__basic_dynamic_body `basic_dynamic_body`] +* [link beast.ref.beast__http__basic_file_body `basic_file_body`] +* [link beast.ref.beast__http__basic_string_body `basic_string_body`] * [link beast.ref.beast__http__buffer_body `buffer_body`] -* [link beast.ref.beast__http__dynamic_body `dynamic_body`] * [link beast.ref.beast__http__empty_body `empty_body`] -* [link beast.ref.beast__http__string_body `string_body`] +* [link beast.ref.beast__http__span_body `span_body`] +* [link beast.ref.beast__http__vector_body `vector_body`] [endsect] diff --git a/doc/qbk/07_concepts/BodyReader.qbk b/doc/qbk/07_concepts/BodyReader.qbk index ec13aa16..0788928f 100644 --- a/doc/qbk/07_concepts/BodyReader.qbk +++ b/doc/qbk/07_concepts/BodyReader.qbk @@ -20,44 +20,39 @@ intended to obtain buffers for these scenarios: * Body data generated dynamically from other threads. * Body data computed algorithmically. -In this table: - -* `X` denotes a type meeting the requirements of [*BodyReader]. - -* `B` denotes a __Body__ where - `std::is_same::value == true`. - -* `a` denotes a value of type `X`. - -* `m` denotes a possibly const value of type `message&` where - `std::is_same:value == true`. - -* `ec` is a value of type [link beast.ref.beast__error_code `error_code&`]. - -* `R` is the type `boost::optional>`. - [heading Associated Types] +* [link beast.ref.beast__http__is_body_reader `is_body_reader`] * __Body__ -* [link beast.ref.beast__http__is_body_reader `is_body_reader`] +[heading Requirements] -[heading BodyReader requirements] -[table Valid Expressions +In this table: + +* `R` denotes a type meeting the requirements of [*BodyReader]. +* `B` denotes a __Body__ where + `std::is_same::value == true`. +* `a` denotes a value of type `R`. +* `m` denotes a possibly const value of type `message&` where + `std::is_same:value == true`. +* `ec` is a value of type [link beast.ref.beast__error_code `error_code&`]. +* `R` is the type `boost::optional>`. + +[table Valid expressions [[Expression] [Type] [Semantics, Pre/Post-conditions]] [ - [`X::const_buffers_type`] + [`R::const_buffers_type`] [] [ A type which meets the requirements of __ConstBufferSequence__. - This is the type of buffer returned by `X::get`. + This is the type of buffer returned by `R::get`. ] ][ - [`X(m);`] + [`R(m);`] [] [ Constructible from `m`. The lifetime of `m` is guaranteed - to end no earlier than after the `X` is destroyed. + to end no earlier than after the `R` is destroyed. The reader shall not access the contents of `m` before the first call to `init`, permitting lazy construction of the message. @@ -65,11 +60,11 @@ In this table: The constructor may optionally require that `m` is const, which has these consequences: - * If `X` requires that `m` is a const reference, then serializers + * If `R` requires that `m` is a const reference, then serializers constructed for messages with this body type will also require a const reference to a message, otherwise: - * If `X` requires that `m` is a non-const reference, then serializers + * If `R` requires that `m` is a non-const reference, then serializers constructed for messages with this body type will aso require a non-const reference to a message. ] @@ -85,7 +80,7 @@ In this table: ] ][ [`a.get(ec)`] - [`R`] + [`R`] [ Called one or more times after `init` succeeds. This function returns `boost::none` if all buffers representing the body have @@ -100,8 +95,7 @@ In this table: The function will ensure that `!ec` is `true` if there was no error or set to the appropriate error code if there was one. ] -] -] +]] [heading Exemplar] @@ -112,6 +106,9 @@ In this table: * [link beast.ref.beast__http__basic_dynamic_body.reader `basic_dynamic_body::reader`] * [link beast.ref.beast__http__basic_file_body__reader `basic_file_body::reader`] * [link beast.ref.beast__http__basic_string_body.reader `basic_string_body::reader`] +* [link beast.ref.beast__http__buffer_body.reader `buffer_body::reader`] * [link beast.ref.beast__http__empty_body.reader `empty_body::reader`] +* [link beast.ref.beast__http__span_body.reader `span_body::reader`] +* [link beast.ref.beast__http__vector_body.reader `vector_body::reader`] [endsect] diff --git a/doc/qbk/07_concepts/BodyWriter.qbk b/doc/qbk/07_concepts/BodyWriter.qbk index 54c93fdc..53fd970d 100644 --- a/doc/qbk/07_concepts/BodyWriter.qbk +++ b/doc/qbk/07_concepts/BodyWriter.qbk @@ -20,37 +20,33 @@ representation: to compress it first. * Saving body data to a file -In this table: - -* `X` denotes a type meeting the requirements of [*BodyWriter]. - -* `B` denotes a __Body__ where - `std::is_same::value == true`. - -* `a` denotes a value of type `X`. - -* `b` is an object whose type meets the requirements of __ConstBufferSequence__ - -* `m` denotes a value of type `message&` where - `std::is_same::value == true`. - -* `n` is a value of type `boost::optional`. - -* `ec` is a value of type [link beast.ref.beast__error_code `error_code&`]. - [heading Associated Types] -* __Body__ * [link beast.ref.beast__http__is_body_writer `is_body_writer`] +* __Body__ -[table Writer requirements -[[expression] [type] [semantics, pre/post-conditions]] +[heading Requirements] + +In this table: + +* `W` denotes a type meeting the requirements of [*BodyWriter]. +* `B` denotes a __Body__ where + `std::is_same::value == true`. +* `a` denotes a value of type `W`. +* `b` is an object whose type meets the requirements of __ConstBufferSequence__ +* `m` denotes a value of type `message&` where + `std::is_same::value == true`. +* `n` is a value of type `boost::optional`. +* `ec` is a value of type [link beast.ref.beast__error_code `error_code&`]. + +[table Valid expressions +[[Expression] [Type] [Semantics, Pre/Post-conditions]] [ - [`X(m);`] + [`W(m);`] [] [ Constructible from `m`. The lifetime of `m` is guaranteed to - end no earlier than after the `X` is destroyed. The constructor + end no earlier than after the `W` is destroyed. The constructor will be called after a complete header is stored in `m`, and before parsing body octets for messages indicating that a body is present The writer shall not access the contents of `m` before @@ -102,8 +98,7 @@ In this table: An alias for `std::true_type` for `B`, otherwise an alias for `std::false_type`. ] -] -] +]] [heading Exemplar] @@ -112,8 +107,11 @@ In this table: [heading Models] * [link beast.ref.beast__http__basic_dynamic_body.writer `basic_dynamic_body::writer`] -* [link beast.ref.beast__http__basic_file_body__reader `basic_file_body::writer`] +* [link beast.ref.beast__http__basic_file_body__writer `basic_file_body::writer`] * [link beast.ref.beast__http__basic_string_body.writer `basic_string_body::writer`] +* [link beast.ref.beast__http__buffer_body.writer `buffer_body::writer`] * [link beast.ref.beast__http__empty_body.writer `empty_body::writer`] +* [link beast.ref.beast__http__span_body.writer `span_body::writer`] +* [link beast.ref.beast__http__vector_body.writer `vector_body::writer`] [endsect] diff --git a/doc/qbk/07_concepts/DynamicBuffer.qbk b/doc/qbk/07_concepts/DynamicBuffer.qbk index d2048a2a..599f512c 100644 --- a/doc/qbk/07_concepts/DynamicBuffer.qbk +++ b/doc/qbk/07_concepts/DynamicBuffer.qbk @@ -31,65 +31,65 @@ implementation strategies: size of the character sequence. This is the implementation approach currently offered by __multi_buffer__. -In this table: +[heading Associated Types] -* `X` denotes a dynamic buffer class. -* `a` denotes a value of type `X`. -* `c` denotes a (possibly const) value of type `X`. +* [link beast.ref.beast__is_dynamic_buffer `is_dynamic_buffer`] +* __ConstBufferSequence__ +* __MutableBufferSequence__ + +[heading Requirements] + +* `D` denotes a dynamic buffer class. +* `a` denotes a value of type `D`. +* `c` denotes a (possibly const) value of type `D`. * `n` denotes a value of type `std::size_t`. * `T` denotes a type meeting the requirements for __ConstBufferSequence__. * `U` denotes a type meeting the requirements for __MutableBufferSequence__. -[table DynamicBuffer requirements -[[expression] [type] [semantics, pre/post-conditions]] +[table Valid expressions +[[Expression] [Type] [Semantics, Pre/Post-conditions]] [ - [`X::const_buffers_type`] + [`D::const_buffers_type`] [`T`] [ This type represents the memory associated with the input sequence. ] -] -[ - [`X::mutable_buffers_type`] +][ + [`D::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`] + [`D::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`] + [`D::mutable_buffers_type`] [ Returns a mutable buffer sequence u representing the output sequence, and where `buffer_size(u) == n`. The dynamic buffer reallocates memory @@ -98,8 +98,7 @@ In this table: Throws: `length_error` if `size() + n` exceeds `max_size()`. ] -] -[ +][ [`a.commit(n)`] [ ] [ @@ -110,8 +109,7 @@ In this table: mutable buffer sequences previously obtained using `data()` or `prepare()` are invalidated. ] -] -[ +][ [`a.consume(n)`] [ ] [ @@ -120,8 +118,7 @@ In this table: is removed. All constant or mutable buffer sequences previously obtained using `data()` or `prepare()` are invalidated. ] -] -] +]] [heading Models] @@ -131,6 +128,8 @@ In this table: * [link beast.ref.beast__flat_buffer `flat_buffer`] * [link beast.ref.beast__flat_static_buffer `flat_static_buffer`] * [link beast.ref.beast__flat_static_buffer_base `flat_static_buffer_base`] +* [link beast.ref.beast__static_buffer `static_buffer`] +* [link beast.ref.beast__static_buffer_base `static_buffer_base`] * [link beast.ref.beast__multi_buffer `multi_buffer`] [endsect] diff --git a/doc/qbk/07_concepts/Fields.qbk b/doc/qbk/07_concepts/Fields.qbk index a66a4282..e200448f 100644 --- a/doc/qbk/07_concepts/Fields.qbk +++ b/doc/qbk/07_concepts/Fields.qbk @@ -15,28 +15,20 @@ be serialized. [heading Associated Types] -* __FieldsReader__ - * [link beast.ref.beast__http__is_fields `is_fields`] +* __FieldsReader__ [heading Requirements] In this table: * `F` denotes a type that meets the requirements of [*Fields]. - * `R` denotes a type meeting the requirements of __FieldsReader__. - * `a` denotes a value of type `F`. - * `c` denotes a (possibly const) value of type `F`. - * `b` is a value of type `bool` - * `n` is a value of type `boost::optional`. - * `s` is a value of type [link beast.ref.beast__string_view `string_view`]. - * `v` is a value of type `unsigned int` representing the HTTP-version. [table Valid expressions diff --git a/doc/qbk/07_concepts/FieldsReader.qbk b/doc/qbk/07_concepts/FieldsReader.qbk index f7fa5fd4..da813dde 100644 --- a/doc/qbk/07_concepts/FieldsReader.qbk +++ b/doc/qbk/07_concepts/FieldsReader.qbk @@ -20,51 +20,45 @@ calls into it once to retrieve the buffers. In this table: -* `X` denotes a type that meets the requirements of [*FieldsReader]. - +* `R` denotes a type that meets the requirements of [*FieldsReader]. * `F` denotes a __Fields__ where - `std::is_same::value == true`. - -* `a` is a value of type `X`. - + `std::is_same::value == true`. +* `a` is a value of type `R`. * `f` is a value of type `F`. - * `v` is an `unsigned` value representing the HTTP version. - * `c` is an `unsigned` representing the HTTP status-code. - * `m` is a value of type [link beast.ref.beast__http__verb `verb`]. [table Valid expressions [[expression][type][semantics, pre/post-conditions]] [ - [`X::const_buffers_type`] + [`R::const_buffers_type`] [] [ A type which meets the requirements of __ConstBufferSequence__. - This is the type of buffer returned by `X::get`. + This is the type of buffer returned by `R::get`. ] ][ - [`X(f,v,m)`] + [`R(f,v,m)`] [] [ The implementation calls this constructor to indicate that the fields being serialized form part of an HTTP request. The lifetime of `f` is guaranteed - to end no earlier than after the `X` is destroyed. + to end no earlier than after the `R` is destroyed. ] ][ - [`X(f,v,c)`] + [`R(f,v,c)`] [] [ The implementation calls this constructor to indicate that the fields being serialized form part of an HTTP response. The lifetime of `f` is guaranteed - to end no earlier than after the `X` is destroyed. + to end no earlier than after the `R` is destroyed. ] ][ [`a.get()`] - [`X::const_buffers_type`] + [`R::const_buffers_type`] [ Called once after construction, this function returns a constant buffer sequence containing the serialized diff --git a/doc/qbk/07_concepts/File.qbk b/doc/qbk/07_concepts/File.qbk index 35decc65..b8e1e3ed 100644 --- a/doc/qbk/07_concepts/File.qbk +++ b/doc/qbk/07_concepts/File.qbk @@ -11,6 +11,13 @@ The [*File] concept abstracts access to files in the underlying file system. To support other platform interfaces, users may author their own [*File] types which meet these requirements. +[heading Associated Types] + +* [link beast.ref.beast__file_mode `file_mode`] +* [link beast.ref.beast__is_file `is_file`] + +[heading Requirements] + In this table: * `F` is a [*File] type @@ -24,13 +31,8 @@ In this table: * `c` is any possibly-const pointer to memory * `ec` is a reference of type [link beast.ref.beast__error_code `error_code`] -[heading Associated Types] - -* [link beast.ref.beast__file_mode `file_mode`] -* [link beast.ref.beast__is_file `is_file`] - -[heading File Requirements] -[table Valid Expressions +[table Valid expressions +[[Expression] [Type] [Semantics, Pre/Post-conditions]] [[Operation] [Return Type] [Semantics, Pre/Post-conditions]] [ [`F()`] @@ -168,6 +170,8 @@ In this table: [heading Models] +* [link beast.ref.beast__file_posix `file_posix`] * [link beast.ref.beast__file_stdio `file_stdio`] +* [link beast.ref.beast__file_win32 `file_win32`] [endsect] diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index 8bbd3559..830b50b8 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -181,19 +181,16 @@ buffers_adapter consuming_buffers drain_buffer - error_category - error_code - error_condition file file_mode file_posix file_stdio + file_win32   - file_win32 flat_buffer flat_static_buffer flat_static_buffer_base @@ -209,7 +206,6 @@ static_string string_param string_view - system_error @@ -225,12 +221,10 @@ ostream read_size read_size_or_throw - system_category to_static_string Constants - errc file_mode @@ -253,6 +247,15 @@ + Aliases + + errc + error_category + error_code + error_condition + system_category + system_error + Concepts AsyncStream @@ -284,6 +287,7 @@ + diff --git a/doc/source.dox b/doc/source.dox index 7ead3bb0..a08b2262 100644 --- a/doc/source.dox +++ b/doc/source.dox @@ -107,8 +107,7 @@ INPUT = \ ../include/beast/core \ ../include/beast/http \ ../include/beast/websocket \ - ../include/beast/zlib \ - ../extras/beast/doc_debug.hpp + ../include/beast/zlib INPUT_ENCODING = UTF-8 FILE_PATTERNS = diff --git a/example/doc/http_examples.hpp b/example/doc/http_examples.hpp index cdb3eb40..e0d6aad6 100644 --- a/example/doc/http_examples.hpp +++ b/example/doc/http_examples.hpp @@ -873,6 +873,7 @@ template class custom_parser : public basic_parser> { +private: // The friend declaration is needed, // otherwise the callbacks must be made public. friend class basic_parser; @@ -915,14 +916,14 @@ class custom_parser content_length, // Content length if known, else `boost::none` error_code& ec); // The error returned to the caller, if any - /** Called for each piece of the body, if a body exists. - - This is used when there is no chunked transfer coding. - - The function returns the number of bytes consumed from the - input buffer. Any input octets not consumed will be will be - presented on subsequent calls. - */ + /// Called for each piece of the body, if a body exists. + //! + //! This is used when there is no chunked transfer coding. + //! + //! The function returns the number of bytes consumed from the + //! input buffer. Any input octets not consumed will be will be + //! presented on subsequent calls. + //! std::size_t on_body_impl( string_view s, // A portion of the body @@ -936,16 +937,16 @@ class custom_parser string_view extension, // The chunk extensions (may be empty) error_code& ec); // The error returned to the caller, if any - /** Called to deliver the chunk body. - - This is used when there is a chunked transfer coding. The - implementation will automatically remove the encoding before - calling this function. - - The function returns the number of bytes consumed from the - input buffer. Any input octets not consumed will be will be - presented on subsequent calls. - */ + /// Called to deliver the chunk body. + //! + //! This is used when there is a chunked transfer coding. The + //! implementation will automatically remove the encoding before + //! calling this function. + //! + //! The function returns the number of bytes consumed from the + //! input buffer. Any input octets not consumed will be will be + //! presented on subsequent calls. + //! std::size_t on_chunk_body_impl( std::uint64_t remain, // The number of bytes remaining in the chunk, diff --git a/include/beast/http/basic_parser.hpp b/include/beast/http/basic_parser.hpp index 256104ec..7decdc20 100644 --- a/include/beast/http/basic_parser.hpp +++ b/include/beast/http/basic_parser.hpp @@ -60,6 +60,103 @@ namespace http { there was one. If an error is set, the value is propagated to the caller of the parser. + @par Derived Class Requirements + @code + template + class derived + : public basic_parser> + { + private: + // The friend declaration is needed, + // otherwise the callbacks must be made public. + friend class basic_parser; + + /// Called after receiving the request-line (isRequest == true). + void + on_request_impl( + verb method, // The method verb, verb::unknown if no match + string_view method_str, // The method as a string + string_view target, // The request-target + int version, // The HTTP-version + error_code& ec); // The error returned to the caller, if any + + /// Called after receiving the start-line (isRequest == false). + void + on_response_impl( + int code, // The status-code + string_view reason, // The obsolete reason-phrase + int version, // The HTTP-version + error_code& ec); // The error returned to the caller, if any + + /// Called after receiving a header field. + void + on_field_impl( + field f, // The known-field enumeration constant + string_view name, // The field name string. + string_view value, // The field value + error_code& ec); // The error returned to the caller, if any + + /// Called after the complete header is received. + void + on_header_impl( + error_code& ec); // The error returned to the caller, if any + + /// Called just before processing the body, if a body exists. + void + on_body_init_impl( + boost::optional< + std::uint64_t> const& + content_length, // Content length if known, else `boost::none` + error_code& ec); // The error returned to the caller, if any + + /// Called for each piece of the body, if a body exists. + //! + //! This is used when there is no chunked transfer coding. + //! + //! The function returns the number of bytes consumed from the + //! input buffer. Any input octets not consumed will be will be + //! presented on subsequent calls. + //! + std::size_t + on_body_impl( + string_view s, // A portion of the body + error_code& ec); // The error returned to the caller, if any + + /// Called for each chunk header. + void + on_chunk_header_impl( + std::uint64_t size, // The size of the upcoming chunk, + // or zero for the last chunk + string_view extension, // The chunk extensions (may be empty) + error_code& ec); // The error returned to the caller, if any + + /// Called to deliver the chunk body. + //! + //! This is used when there is a chunked transfer coding. The + //! implementation will automatically remove the encoding before + //! calling this function. + //! + //! The function returns the number of bytes consumed from the + //! input buffer. Any input octets not consumed will be will be + //! presented on subsequent calls. + //! + std::size_t + on_chunk_body_impl( + std::uint64_t remain, // The number of bytes remaining in the chunk, + // including what is being passed here. + // or zero for the last chunk + string_view body, // The next piece of the chunk body + error_code& ec); // The error returned to the caller, if any + + /// Called when the complete message is parsed. + void + on_finish_impl(error_code& ec); + + public: + derived() = default; + }; + @endcode + @tparam isRequest A `bool` indicating whether the parser will be presented with request or response message. diff --git a/include/beast/http/fields.hpp b/include/beast/http/fields.hpp index 6ddfd826..3f95b154 100644 --- a/include/beast/http/fields.hpp +++ b/include/beast/http/fields.hpp @@ -257,6 +257,9 @@ public: /** Returns the value for a field, or throws an exception. + If more than one field with the specified name exists, the + first field defined by insertion order is returned. + @param name The name of the field. @return The field value. @@ -268,6 +271,9 @@ public: /** Returns the value for a field, or throws an exception. + If more than one field with the specified name exists, the + first field defined by insertion order is returned. + @param name The name of the field. @return The field value. diff --git a/include/beast/http/string_body.hpp b/include/beast/http/string_body.hpp index cdeaec7c..0104f5f1 100644 --- a/include/beast/http/string_body.hpp +++ b/include/beast/http/string_body.hpp @@ -156,11 +156,11 @@ public: { using boost::asio::buffer_size; using boost::asio::buffer_copy; - auto const n = buffer_size(buffers); - auto const len = body_.size(); + auto const extra = buffer_size(buffers); + auto const size = body_.size(); try { - body_.resize(len + n); + body_.resize(size + extra); } catch(std::exception const&) { @@ -168,8 +168,16 @@ public: return 0; } ec.assign(0, ec.category()); - return buffer_copy(boost::asio::buffer( - &body_[0] + len, n), buffers); + CharT* dest = &body_[size]; + for(boost::asio::const_buffer b : buffers) + { + using boost::asio::buffer_cast; + auto const len = boost::asio::buffer_size(b); + Traits::copy( + dest, buffer_cast(b), len); + dest += len; + } + return extra; } void diff --git a/test/exemplars.cpp b/test/exemplars.cpp index 9a8256a4..401b6923 100644 --- a/test/exemplars.cpp +++ b/test/exemplars.cpp @@ -27,15 +27,15 @@ struct Body struct value_type; /// The algorithm used for extracting buffers - using reader = BodyReader; + class reader; /// The algorithm used for inserting buffers - using writer = BodyWriter; + class writer; /// Returns the body's payload size static std::uint64_t - size(value_type const& v); + size(value_type const& body); }; static_assert(is_body::value, "");