mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-26 22:15:52 +00:00
Beast.HTTP:
New classes are introduced to represent HTTP messages and their associated bodies. The parser interface is reworked to use CRTP, error codes, and trait checks. New classes: * basic_headers Models field/value pairs in a HTTP message. * message Models a HTTP message, body behavior defined by template argument. Parsed message carries metadata generated during parsing. * parser Produces parsed messages. * empty_body, string_body, basic_streambuf_body Classes used to represent content bodies in various ways. New functions: * read, async_read, write, async_write Read and write HTTP messages on a socket. New concepts: * Body: Represents the HTTP Content-Body. * Field: A HTTP header field. * FieldSequence: A forward sequence of fields. * Reader: Parses a Body from a stream of bytes. * Writer: Serializes a Body to buffers. basic_parser changes: * add write methods which throw exceptions instead * error_code passed via parameter instead of return value * fold private member calls into existing callbacks * basic_parser uses CRTP instead of virtual members * add documentation on Derived requirements for CRTP impl/http-parser changes: * joyent renamed to nodejs to reflect upstream changes
This commit is contained in:
@@ -246,6 +246,8 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\asio\buffers_adapter.h">
|
<ClInclude Include="..\..\src\beast\beast\asio\buffers_adapter.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\asio\buffers_debug.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\asio\consuming_buffers.h">
|
<ClInclude Include="..\..\src\beast\beast\asio\consuming_buffers.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\asio\handler_alloc.h">
|
<ClInclude Include="..\..\src\beast\beast\asio\handler_alloc.h">
|
||||||
@@ -361,62 +363,88 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\hash\xxhasher.h">
|
<ClInclude Include="..\..\src\beast\beast\hash\xxhasher.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\basic_headers.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\basic_parser.h">
|
<ClInclude Include="..\..\src\beast\beast\http\basic_parser.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\body.h">
|
<ClInclude Include="..\..\src\beast\beast\http\body.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\chunk_encode.h">
|
<ClInclude Include="..\..\src\beast\beast\http\chunk_encode.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\detail\error.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\detail\writes.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\detail\write_preparation.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\empty_body.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\error.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\fields.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\headers.h">
|
<ClInclude Include="..\..\src\beast\beast\http\headers.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\HTTP.unity.cpp">
|
<None Include="..\..\src\beast\beast\http\impl\basic_headers.ipp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
</None>
|
||||||
</ClCompile>
|
<None Include="..\..\src\beast\beast\http\impl\basic_parser.ipp">
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\basic_parser.cpp">
|
</None>
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.c">
|
<ClCompile Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.c">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.h">
|
<ClInclude Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\joyent_parser.cpp">
|
<None Include="..\..\src\beast\beast\http\impl\message.ipp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
</None>
|
||||||
</ClCompile>
|
<None Include="..\..\src\beast\beast\http\impl\read.ipp">
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\impl\joyent_parser.h">
|
</None>
|
||||||
</ClInclude>
|
<None Include="..\..\src\beast\beast\http\impl\write.ipp">
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\method.cpp">
|
</None>
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\URL.cpp">
|
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\message.h">
|
<ClInclude Include="..\..\src\beast\beast\http\message.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\method.h">
|
<ClInclude Include="..\..\src\beast\beast\http\method.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\parser.h">
|
<ClInclude Include="..\..\src\beast\beast\http\parser.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\read.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\reason.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\resume_context.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\rfc2616.h">
|
<ClInclude Include="..\..\src\beast\beast\http\rfc2616.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\chunked_encoder.test.cpp">
|
<ClCompile Include="..\..\src\beast\beast\http\src\beast_http_nodejs_parser.cpp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\parser.test.cpp">
|
<ClInclude Include="..\..\src\beast\beast\http\src\nodejs_parser.h">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\rfc2616.test.cpp">
|
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\URL.test.cpp">
|
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\urls_large_data.cpp">
|
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\tests\urls_large_data.h">
|
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\URL.h">
|
<ClCompile Include="..\..\src\beast\beast\http\src\test\beast_http_chunked_encoder_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\beast\beast\http\src\test\beast_http_message_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\beast\beast\http\src\test\beast_http_parser_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\beast\beast\http\src\test\beast_http_rfc2616_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\streambuf_body.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\string_body.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\type_check.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\write.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\is_call_possible.h">
|
<ClInclude Include="..\..\src\beast\beast\is_call_possible.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -454,6 +482,10 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\beast\beast\unity\beast_hash_unity.cpp">
|
<ClCompile Include="..\..\src\beast\beast\unity\beast_hash_unity.cpp">
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\beast\beast\unity\beast_http_unity.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\beast\beast\unity\beast_streams_unity.cpp">
|
<ClCompile Include="..\..\src\beast\beast\unity\beast_streams_unity.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
@@ -1728,6 +1760,10 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\ripple\beast\net\impl\URL.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\beast\net\IPAddress.h">
|
<ClInclude Include="..\..\src\ripple\beast\net\IPAddress.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\beast\net\IPAddressConversion.h">
|
<ClInclude Include="..\..\src\ripple\beast\net\IPAddressConversion.h">
|
||||||
@@ -1738,10 +1774,16 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\beast\net\IPEndpoint.h">
|
<ClInclude Include="..\..\src\ripple\beast\net\IPEndpoint.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\beast\net\tests\beast_http_URL_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\beast\net\tests\IPEndpoint.test.cpp">
|
<ClCompile Include="..\..\src\ripple\beast\net\tests\IPEndpoint.test.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\beast\net\URL.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\beast\nudb.h">
|
<ClInclude Include="..\..\src\ripple\beast\nudb.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\beast\nudb\api.h">
|
<ClInclude Include="..\..\src\ripple\beast\nudb\api.h">
|
||||||
|
|||||||
@@ -49,14 +49,20 @@
|
|||||||
<Filter Include="beast\http">
|
<Filter Include="beast\http">
|
||||||
<UniqueIdentifier>{7138D215-DA65-98D5-EF7D-C9896685201E}</UniqueIdentifier>
|
<UniqueIdentifier>{7138D215-DA65-98D5-EF7D-C9896685201E}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="beast\http\detail">
|
||||||
|
<UniqueIdentifier>{3E84AA4C-CB48-99F0-EB35-5603FF633A51}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="beast\http\impl">
|
<Filter Include="beast\http\impl">
|
||||||
<UniqueIdentifier>{932F732F-F09E-5C50-C8A1-D62342CCAA1F}</UniqueIdentifier>
|
<UniqueIdentifier>{932F732F-F09E-5C50-C8A1-D62342CCAA1F}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="beast\http\impl\http-parser">
|
<Filter Include="beast\http\impl\http-parser">
|
||||||
<UniqueIdentifier>{59E40DE8-464F-35ED-5F22-E7B52FDE3ECD}</UniqueIdentifier>
|
<UniqueIdentifier>{59E40DE8-464F-35ED-5F22-E7B52FDE3ECD}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="beast\http\tests">
|
<Filter Include="beast\http\src">
|
||||||
<UniqueIdentifier>{7FFB535D-F2F1-0B27-4C2F-28A6BAFDE4ED}</UniqueIdentifier>
|
<UniqueIdentifier>{CCA07C08-BF91-95E2-4980-7D56A618C37E}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast\http\src\test">
|
||||||
|
<UniqueIdentifier>{5F7F2E0C-4CDE-B1E1-1668-E06768D6FFD3}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="beast\streams">
|
<Filter Include="beast\streams">
|
||||||
<UniqueIdentifier>{7944CEAB-F8F9-1E2B-CD03-B3D9F78B20E9}</UniqueIdentifier>
|
<UniqueIdentifier>{7944CEAB-F8F9-1E2B-CD03-B3D9F78B20E9}</UniqueIdentifier>
|
||||||
@@ -552,6 +558,9 @@
|
|||||||
<ClInclude Include="..\..\src\beast\beast\asio\buffers_adapter.h">
|
<ClInclude Include="..\..\src\beast\beast\asio\buffers_adapter.h">
|
||||||
<Filter>beast\asio</Filter>
|
<Filter>beast\asio</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\asio\buffers_debug.h">
|
||||||
|
<Filter>beast\asio</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\asio\consuming_buffers.h">
|
<ClInclude Include="..\..\src\beast\beast\asio\consuming_buffers.h">
|
||||||
<Filter>beast\asio</Filter>
|
<Filter>beast\asio</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -699,6 +708,12 @@
|
|||||||
<ClInclude Include="..\..\src\beast\beast\hash\xxhasher.h">
|
<ClInclude Include="..\..\src\beast\beast\hash\xxhasher.h">
|
||||||
<Filter>beast\hash</Filter>
|
<Filter>beast\hash</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http.h">
|
||||||
|
<Filter>beast</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\basic_headers.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\basic_parser.h">
|
<ClInclude Include="..\..\src\beast\beast\http\basic_parser.h">
|
||||||
<Filter>beast\http</Filter>
|
<Filter>beast\http</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -708,33 +723,48 @@
|
|||||||
<ClInclude Include="..\..\src\beast\beast\http\chunk_encode.h">
|
<ClInclude Include="..\..\src\beast\beast\http\chunk_encode.h">
|
||||||
<Filter>beast\http</Filter>
|
<Filter>beast\http</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\detail\error.h">
|
||||||
|
<Filter>beast\http\detail</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\detail\writes.h">
|
||||||
|
<Filter>beast\http\detail</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\detail\write_preparation.h">
|
||||||
|
<Filter>beast\http\detail</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\empty_body.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\error.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\fields.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\headers.h">
|
<ClInclude Include="..\..\src\beast\beast\http\headers.h">
|
||||||
<Filter>beast\http</Filter>
|
<Filter>beast\http</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\HTTP.unity.cpp">
|
<None Include="..\..\src\beast\beast\http\impl\basic_headers.ipp">
|
||||||
<Filter>beast\http</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\basic_parser.cpp">
|
|
||||||
<Filter>beast\http\impl</Filter>
|
<Filter>beast\http\impl</Filter>
|
||||||
</ClCompile>
|
</None>
|
||||||
|
<None Include="..\..\src\beast\beast\http\impl\basic_parser.ipp">
|
||||||
|
<Filter>beast\http\impl</Filter>
|
||||||
|
</None>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.c">
|
<ClCompile Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.c">
|
||||||
<Filter>beast\http\impl\http-parser</Filter>
|
<Filter>beast\http\impl\http-parser</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.h">
|
<ClInclude Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.h">
|
||||||
<Filter>beast\http\impl\http-parser</Filter>
|
<Filter>beast\http\impl\http-parser</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\joyent_parser.cpp">
|
<None Include="..\..\src\beast\beast\http\impl\message.ipp">
|
||||||
<Filter>beast\http\impl</Filter>
|
<Filter>beast\http\impl</Filter>
|
||||||
</ClCompile>
|
</None>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\impl\joyent_parser.h">
|
<None Include="..\..\src\beast\beast\http\impl\read.ipp">
|
||||||
<Filter>beast\http\impl</Filter>
|
<Filter>beast\http\impl</Filter>
|
||||||
</ClInclude>
|
</None>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\method.cpp">
|
<None Include="..\..\src\beast\beast\http\impl\write.ipp">
|
||||||
<Filter>beast\http\impl</Filter>
|
<Filter>beast\http\impl</Filter>
|
||||||
</ClCompile>
|
</None>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\impl\URL.cpp">
|
|
||||||
<Filter>beast\http\impl</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\message.h">
|
<ClInclude Include="..\..\src\beast\beast\http\message.h">
|
||||||
<Filter>beast\http</Filter>
|
<Filter>beast\http</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -744,28 +774,46 @@
|
|||||||
<ClInclude Include="..\..\src\beast\beast\http\parser.h">
|
<ClInclude Include="..\..\src\beast\beast\http\parser.h">
|
||||||
<Filter>beast\http</Filter>
|
<Filter>beast\http</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\read.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\reason.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\resume_context.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\rfc2616.h">
|
<ClInclude Include="..\..\src\beast\beast\http\rfc2616.h">
|
||||||
<Filter>beast\http</Filter>
|
<Filter>beast\http</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\chunked_encoder.test.cpp">
|
<ClCompile Include="..\..\src\beast\beast\http\src\beast_http_nodejs_parser.cpp">
|
||||||
<Filter>beast\http\tests</Filter>
|
<Filter>beast\http\src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\parser.test.cpp">
|
<ClInclude Include="..\..\src\beast\beast\http\src\nodejs_parser.h">
|
||||||
<Filter>beast\http\tests</Filter>
|
<Filter>beast\http\src</Filter>
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\rfc2616.test.cpp">
|
|
||||||
<Filter>beast\http\tests</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\URL.test.cpp">
|
|
||||||
<Filter>beast\http\tests</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\beast\beast\http\tests\urls_large_data.cpp">
|
|
||||||
<Filter>beast\http\tests</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\tests\urls_large_data.h">
|
|
||||||
<Filter>beast\http\tests</Filter>
|
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\http\URL.h">
|
<ClCompile Include="..\..\src\beast\beast\http\src\test\beast_http_chunked_encoder_test.cpp">
|
||||||
|
<Filter>beast\http\src\test</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\beast\beast\http\src\test\beast_http_message_test.cpp">
|
||||||
|
<Filter>beast\http\src\test</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\beast\beast\http\src\test\beast_http_parser_test.cpp">
|
||||||
|
<Filter>beast\http\src\test</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\beast\beast\http\src\test\beast_http_rfc2616_test.cpp">
|
||||||
|
<Filter>beast\http\src\test</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\streambuf_body.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\string_body.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\type_check.h">
|
||||||
|
<Filter>beast\http</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\beast\beast\http\write.h">
|
||||||
<Filter>beast\http</Filter>
|
<Filter>beast\http</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\beast\beast\is_call_possible.h">
|
<ClInclude Include="..\..\src\beast\beast\is_call_possible.h">
|
||||||
@@ -807,6 +855,9 @@
|
|||||||
<ClCompile Include="..\..\src\beast\beast\unity\beast_hash_unity.cpp">
|
<ClCompile Include="..\..\src\beast\beast\unity\beast_hash_unity.cpp">
|
||||||
<Filter>beast\unity</Filter>
|
<Filter>beast\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\beast\beast\unity\beast_http_unity.cpp">
|
||||||
|
<Filter>beast\unity</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\beast\beast\unity\beast_streams_unity.cpp">
|
<ClCompile Include="..\..\src\beast\beast\unity\beast_streams_unity.cpp">
|
||||||
<Filter>beast\unity</Filter>
|
<Filter>beast\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -2211,6 +2262,9 @@
|
|||||||
<ClCompile Include="..\..\src\ripple\beast\net\impl\IPEndpoint.cpp">
|
<ClCompile Include="..\..\src\ripple\beast\net\impl\IPEndpoint.cpp">
|
||||||
<Filter>ripple\beast\net\impl</Filter>
|
<Filter>ripple\beast\net\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\ripple\beast\net\impl\URL.cpp">
|
||||||
|
<Filter>ripple\beast\net\impl</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\beast\net\IPAddress.h">
|
<ClInclude Include="..\..\src\ripple\beast\net\IPAddress.h">
|
||||||
<Filter>ripple\beast\net</Filter>
|
<Filter>ripple\beast\net</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -2226,9 +2280,15 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\beast\net\IPEndpoint.h">
|
<ClInclude Include="..\..\src\ripple\beast\net\IPEndpoint.h">
|
||||||
<Filter>ripple\beast\net</Filter>
|
<Filter>ripple\beast\net</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\beast\net\tests\beast_http_URL_test.cpp">
|
||||||
|
<Filter>ripple\beast\net\tests</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\beast\net\tests\IPEndpoint.test.cpp">
|
<ClCompile Include="..\..\src\ripple\beast\net\tests\IPEndpoint.test.cpp">
|
||||||
<Filter>ripple\beast\net\tests</Filter>
|
<Filter>ripple\beast\net\tests</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\beast\net\URL.h">
|
||||||
|
<Filter>ripple\beast\net</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\beast\nudb.h">
|
<ClInclude Include="..\..\src\ripple\beast\nudb.h">
|
||||||
<Filter>ripple\beast</Filter>
|
<Filter>ripple\beast</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@@ -904,6 +904,7 @@ def get_classic_sources(toolchain):
|
|||||||
append_sources(result, *list_sources('src/beast/beast/asio/src', '.cpp'))
|
append_sources(result, *list_sources('src/beast/beast/asio/src', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/beast/beast/clock', '.cpp'))
|
append_sources(result, *list_sources('src/beast/beast/clock', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/beast/beast/crypto', '.cpp'))
|
append_sources(result, *list_sources('src/beast/beast/crypto', '.cpp'))
|
||||||
|
append_sources(result, *list_sources('src/beast/beast/http/src', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/beast/beast/streams', '.cpp'))
|
append_sources(result, *list_sources('src/beast/beast/streams', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/beast/beast/test', '.cpp'))
|
append_sources(result, *list_sources('src/beast/beast/test', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/beast/container', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/beast/container', '.cpp'))
|
||||||
@@ -953,6 +954,7 @@ def get_unity_sources(toolchain):
|
|||||||
'src/beast/beast/unity/beast_asio_unity.cpp',
|
'src/beast/beast/unity/beast_asio_unity.cpp',
|
||||||
'src/beast/beast/unity/beast_clock_unity.cpp',
|
'src/beast/beast/unity/beast_clock_unity.cpp',
|
||||||
'src/beast/beast/unity/beast_crypto_unity.cpp',
|
'src/beast/beast/unity/beast_crypto_unity.cpp',
|
||||||
|
'src/beast/beast/unity/beast_http_unity.cpp',
|
||||||
'src/beast/beast/unity/beast_streams_unity.cpp',
|
'src/beast/beast/unity/beast_streams_unity.cpp',
|
||||||
'src/beast/beast/unity/beast_test_unity.cpp',
|
'src/beast/beast/unity/beast_test_unity.cpp',
|
||||||
'src/ripple/beast/unity/beast_container_unity.cpp',
|
'src/ripple/beast/unity/beast_container_unity.cpp',
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ project beast
|
|||||||
<include>.
|
<include>.
|
||||||
#<use>/boost//headers
|
#<use>/boost//headers
|
||||||
<library>/boost/system//boost_system
|
<library>/boost/system//boost_system
|
||||||
|
<library>/boost/filesystem//boost_filesystem
|
||||||
|
<library>/boost/program_options//boost_program_options
|
||||||
|
# <library>ssl
|
||||||
|
# <library>crypto
|
||||||
<define>BOOST_ALL_NO_LIB=1
|
<define>BOOST_ALL_NO_LIB=1
|
||||||
<threading>multi
|
<threading>multi
|
||||||
<link>static
|
<link>static
|
||||||
@@ -61,6 +65,8 @@ project beast
|
|||||||
<os>HPUX:<library>ipv6
|
<os>HPUX:<library>ipv6
|
||||||
<os>QNXNTO:<library>socket
|
<os>QNXNTO:<library>socket
|
||||||
<os>HAIKU:<library>network
|
<os>HAIKU:<library>network
|
||||||
|
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||||
|
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||||
: usage-requirements
|
: usage-requirements
|
||||||
<include>.
|
<include>.
|
||||||
:
|
:
|
||||||
|
|||||||
1
src/beast/README.md
Normal file
1
src/beast/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Beast: A C++ Library
|
||||||
@@ -1 +0,0 @@
|
|||||||
# Beast: An amazing cross platform library
|
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#ifndef BEAST_UTILITY_CI_CHAR_TRAITS_H_INCLUDED
|
#ifndef BEAST_UTILITY_CI_CHAR_TRAITS_H_INCLUDED
|
||||||
#define BEAST_UTILITY_CI_CHAR_TRAITS_H_INCLUDED
|
#define BEAST_UTILITY_CI_CHAR_TRAITS_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/utility/string_ref.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@@ -34,16 +35,15 @@ struct ci_less
|
|||||||
{
|
{
|
||||||
static bool const is_transparent = true;
|
static bool const is_transparent = true;
|
||||||
|
|
||||||
template <class String>
|
|
||||||
bool
|
bool
|
||||||
operator() (String const& lhs, String const& rhs) const
|
operator()(boost::string_ref const& lhs,
|
||||||
|
boost::string_ref const& rhs) const noexcept
|
||||||
{
|
{
|
||||||
using std::begin;
|
using std::begin;
|
||||||
using std::end;
|
using std::end;
|
||||||
using char_type = typename String::value_type;
|
return std::lexicographical_compare(
|
||||||
return std::lexicographical_compare (
|
|
||||||
begin(lhs), end(lhs), begin(rhs), end(rhs),
|
begin(lhs), end(lhs), begin(rhs), end(rhs),
|
||||||
[] (char_type lhs, char_type rhs)
|
[](char lhs, char rhs)
|
||||||
{
|
{
|
||||||
return std::tolower(lhs) < std::tolower(rhs);
|
return std::tolower(lhs) < std::tolower(rhs);
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/beast/beast/http.h
Normal file
39
src/beast/beast/http.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/basic_parser.h>
|
||||||
|
#include <beast/http/chunk_encode.h>
|
||||||
|
#include <beast/http/empty_body.h>
|
||||||
|
#include <beast/http/error.h>
|
||||||
|
#include <beast/http/fields.h>
|
||||||
|
#include <beast/http/headers.h>
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <beast/http/parser.h>
|
||||||
|
#include <beast/http/read.h>
|
||||||
|
#include <beast/http/reason.h>
|
||||||
|
#include <beast/http/resume_context.h>
|
||||||
|
#include <beast/http/streambuf_body.h>
|
||||||
|
#include <beast/http/string_body.h>
|
||||||
|
#include <beast/http/type_check.h>
|
||||||
|
#include <beast/http/write.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
447
src/beast/beast/http/basic_headers.h
Normal file
447
src/beast/beast/http/basic_headers.h
Normal file
@@ -0,0 +1,447 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_BASIC_HEADERS_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_BASIC_HEADERS_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/detail/writes.h>
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
#include <beast/ci_char_traits.h>
|
||||||
|
#include <beast/empty_base_optimization.h>
|
||||||
|
#include <boost/intrusive/list.hpp>
|
||||||
|
#include <boost/intrusive/set.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <boost/utility/string_ref.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <beast/cxx17/type_traits.h> // <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_headers;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class basic_headers_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct value_type
|
||||||
|
{
|
||||||
|
std::string first;
|
||||||
|
std::string second;
|
||||||
|
|
||||||
|
value_type(boost::string_ref const& name_,
|
||||||
|
boost::string_ref const& value_)
|
||||||
|
: first(name_)
|
||||||
|
, second(value_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::string_ref
|
||||||
|
name() const
|
||||||
|
{
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::string_ref
|
||||||
|
value() const
|
||||||
|
{
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<class Allocator>
|
||||||
|
friend class beast::http::basic_headers;
|
||||||
|
|
||||||
|
struct element
|
||||||
|
: boost::intrusive::set_base_hook <
|
||||||
|
boost::intrusive::link_mode <
|
||||||
|
boost::intrusive::normal_link>>
|
||||||
|
, boost::intrusive::list_base_hook <
|
||||||
|
boost::intrusive::link_mode <
|
||||||
|
boost::intrusive::normal_link>>
|
||||||
|
{
|
||||||
|
value_type data;
|
||||||
|
|
||||||
|
element(boost::string_ref const& name,
|
||||||
|
boost::string_ref const& value)
|
||||||
|
: data(name, value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct less : private ci_less
|
||||||
|
{
|
||||||
|
template<class String>
|
||||||
|
bool
|
||||||
|
operator()(String const& lhs, element const& rhs) const
|
||||||
|
{
|
||||||
|
return ci_less::operator()(lhs, rhs.data.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class String>
|
||||||
|
bool
|
||||||
|
operator()(element const& lhs, String const& rhs) const
|
||||||
|
{
|
||||||
|
return ci_less::operator()(lhs.data.first, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator()(element const& lhs, element const& rhs) const
|
||||||
|
{
|
||||||
|
return beast::ci_less::operator()(
|
||||||
|
lhs.data.first, rhs.data.first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using list_t = typename boost::intrusive::make_list<
|
||||||
|
element, boost::intrusive::constant_time_size<false>>::type;
|
||||||
|
|
||||||
|
using set_t = typename boost::intrusive::make_set<
|
||||||
|
element, boost::intrusive::constant_time_size<true>,
|
||||||
|
boost::intrusive::compare<less>>::type;
|
||||||
|
|
||||||
|
// data
|
||||||
|
set_t set_;
|
||||||
|
list_t list_;
|
||||||
|
|
||||||
|
basic_headers_base(set_t&& set, list_t&& list)
|
||||||
|
: set_(std::move(set))
|
||||||
|
, list_(std::move(list))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
using iterator = const_iterator;
|
||||||
|
|
||||||
|
basic_headers_base() = default;
|
||||||
|
|
||||||
|
/// Returns an iterator to the beginning of the field sequence.
|
||||||
|
iterator
|
||||||
|
begin() const;
|
||||||
|
|
||||||
|
/// Returns an iterator to the end of the field sequence.
|
||||||
|
iterator
|
||||||
|
end() const;
|
||||||
|
|
||||||
|
/// Returns an iterator to the beginning of the field sequence.
|
||||||
|
iterator
|
||||||
|
cbegin() const;
|
||||||
|
|
||||||
|
/// Returns an iterator to the end of the field sequence.
|
||||||
|
iterator
|
||||||
|
cend() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class basic_headers_base::const_iterator
|
||||||
|
{
|
||||||
|
using iter_type = list_t::const_iterator;
|
||||||
|
|
||||||
|
iter_type it_;
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
friend class beast::http::basic_headers;
|
||||||
|
|
||||||
|
friend class basic_headers_base;
|
||||||
|
|
||||||
|
const_iterator(iter_type it)
|
||||||
|
: it_(it)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type =
|
||||||
|
typename basic_headers_base::value_type;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type const&;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return it_ == other.it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return it_->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const
|
||||||
|
{
|
||||||
|
return &**this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Container to store HTTP headers.
|
||||||
|
|
||||||
|
Meets the requirements of `FieldSequence`.
|
||||||
|
*/
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_headers
|
||||||
|
#if ! GENERATING_DOCS
|
||||||
|
: private empty_base_optimization<
|
||||||
|
typename std::allocator_traits<Allocator>::
|
||||||
|
template rebind_alloc<
|
||||||
|
detail::basic_headers_base::element>>
|
||||||
|
, public detail::basic_headers_base
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
using alloc_type = typename
|
||||||
|
std::allocator_traits<Allocator>::
|
||||||
|
template rebind_alloc<
|
||||||
|
detail::basic_headers_base::element>;
|
||||||
|
|
||||||
|
using alloc_traits =
|
||||||
|
std::allocator_traits<alloc_type>;
|
||||||
|
|
||||||
|
using size_type =
|
||||||
|
typename std::allocator_traits<Allocator>::size_type;
|
||||||
|
|
||||||
|
void
|
||||||
|
delete_all();
|
||||||
|
|
||||||
|
void
|
||||||
|
move_assign(basic_headers&, std::false_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
move_assign(basic_headers&, std::true_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_assign(basic_headers const&, std::false_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_assign(basic_headers const&, std::true_type);
|
||||||
|
|
||||||
|
template<class FieldSequence>
|
||||||
|
void
|
||||||
|
copy_from(FieldSequence const& fs)
|
||||||
|
{
|
||||||
|
for(auto const& e : fs)
|
||||||
|
insert(e.first, e.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type of allocator used.
|
||||||
|
using allocator_type = Allocator;
|
||||||
|
|
||||||
|
/// Default constructor.
|
||||||
|
basic_headers() = default;
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~basic_headers();
|
||||||
|
|
||||||
|
/** Construct the headers.
|
||||||
|
|
||||||
|
@param alloc The allocator to use.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
basic_headers(Allocator const& alloc);
|
||||||
|
|
||||||
|
/** Move constructor.
|
||||||
|
|
||||||
|
The moved-from object becomes an empty field sequence.
|
||||||
|
|
||||||
|
@param other The object to move from.
|
||||||
|
*/
|
||||||
|
basic_headers(basic_headers&& other);
|
||||||
|
|
||||||
|
/** Move assignment.
|
||||||
|
|
||||||
|
The moved-from object becomes an empty field sequence.
|
||||||
|
|
||||||
|
@param other The object to move from.
|
||||||
|
*/
|
||||||
|
basic_headers& operator=(basic_headers&& other);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
basic_headers(basic_headers const&);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
basic_headers& operator=(basic_headers const&);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_headers(basic_headers<OtherAlloc> const&);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_headers& operator=(basic_headers<OtherAlloc> const&);
|
||||||
|
|
||||||
|
/// Construct from a field sequence.
|
||||||
|
template<class FwdIt>
|
||||||
|
basic_headers(FwdIt first, FwdIt last);
|
||||||
|
|
||||||
|
/// Returns `true` if the field sequence contains no elements.
|
||||||
|
bool
|
||||||
|
empty() const
|
||||||
|
{
|
||||||
|
return set_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of elements in the field sequence.
|
||||||
|
std::size_t
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return set_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns `true` if the specified field exists. */
|
||||||
|
bool
|
||||||
|
exists(boost::string_ref const& name) const
|
||||||
|
{
|
||||||
|
return set_.find(name, less{}) != set_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns an iterator to the case-insensitive matching header. */
|
||||||
|
iterator
|
||||||
|
find(boost::string_ref const& name) const;
|
||||||
|
|
||||||
|
/** Returns the value for a case-insensitive matching header, or "" */
|
||||||
|
boost::string_ref
|
||||||
|
operator[](boost::string_ref const& name) const;
|
||||||
|
|
||||||
|
/** Clear the contents of the basic_headers. */
|
||||||
|
void
|
||||||
|
clear() noexcept;
|
||||||
|
|
||||||
|
/** Remove a field.
|
||||||
|
|
||||||
|
@return The number of fields removed.
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
erase(boost::string_ref const& name);
|
||||||
|
|
||||||
|
/** Insert a field value.
|
||||||
|
|
||||||
|
If a field value already exists the new value will be
|
||||||
|
extended as per RFC2616 Section 4.2.
|
||||||
|
*/
|
||||||
|
// VFALCO TODO Consider allowing rvalue references for std::move?
|
||||||
|
void
|
||||||
|
insert(boost::string_ref const& name,
|
||||||
|
boost::string_ref const& 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 = std::enable_if_t<
|
||||||
|
! std::is_constructible<boost::string_ref, T>::value>>
|
||||||
|
void
|
||||||
|
insert(boost::string_ref name, T const& value)
|
||||||
|
{
|
||||||
|
insert(name,
|
||||||
|
boost::lexical_cast<std::string>(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).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
replace(boost::string_ref const& name,
|
||||||
|
boost::string_ref const& 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).
|
||||||
|
*/
|
||||||
|
template<class T,
|
||||||
|
class = std::enable_if_t<
|
||||||
|
! std::is_constructible<boost::string_ref, T>::value>>
|
||||||
|
void
|
||||||
|
replace(boost::string_ref const& name, T const& value)
|
||||||
|
{
|
||||||
|
replace(name,
|
||||||
|
boost::lexical_cast<std::string>(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/http/impl/basic_headers.ipp>
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -21,66 +21,84 @@
|
|||||||
#define BEAST_HTTP_BASIC_PARSER_H_INCLUDED
|
#define BEAST_HTTP_BASIC_PARSER_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/http/method.h>
|
#include <beast/http/method.h>
|
||||||
|
#include <beast/http/src/nodejs_parser.h>
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <beast/cxx17/type_traits.h> // <type_traits>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
namespace joyent {
|
|
||||||
struct http_parser;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
|
/** Parser for producing HTTP requests and responses.
|
||||||
|
|
||||||
|
Callbacks:
|
||||||
|
|
||||||
|
If a is an object of type Derived, and the call expression is
|
||||||
|
valid then the stated effects will take place:
|
||||||
|
|
||||||
|
a.on_start()
|
||||||
|
|
||||||
|
Called once when a new message begins.
|
||||||
|
|
||||||
|
a.on_field(std::string field, std::string value)
|
||||||
|
|
||||||
|
Called for each field
|
||||||
|
|
||||||
|
a.on_headers_complete(error_code&)
|
||||||
|
|
||||||
|
Called when all the header fields have been received, but
|
||||||
|
before any part of the body if any is received.
|
||||||
|
|
||||||
|
a.on_request(method_t method, std::string url,
|
||||||
|
int major, int minor, bool keep_alive, bool upgrade)
|
||||||
|
|
||||||
|
Called for requests when all the headers have been received.
|
||||||
|
This will precede any content body.
|
||||||
|
|
||||||
|
When keep_alive is false:
|
||||||
|
* Server roles respond with a "Connection: close" header.
|
||||||
|
* Client roles close the connection.
|
||||||
|
|
||||||
|
a.on_response(int status, std::string text,
|
||||||
|
int major, int minor, bool keep_alive,
|
||||||
|
bool upgrade)
|
||||||
|
|
||||||
|
Called for responses when all the headers have been received.
|
||||||
|
This will precede any content body.
|
||||||
|
|
||||||
|
When keep_alive is `false`:
|
||||||
|
* Client roles close the connection.
|
||||||
|
* Server roles respond with a "Connection: close" header.
|
||||||
|
|
||||||
|
This function should return `true` if upgrade is false and
|
||||||
|
a content body is expected. When upgrade is true, no
|
||||||
|
content-body is expected, and the return value is ignored.
|
||||||
|
|
||||||
|
a.on_body(void const* data, std::size_t bytes, error_code&)
|
||||||
|
|
||||||
|
Called zero or more times for the content body. Any transfer
|
||||||
|
encoding is already decoded in the memory pointed to by data.
|
||||||
|
|
||||||
|
a.on_complete()
|
||||||
|
|
||||||
|
Called when parsing completes successfully.
|
||||||
|
|
||||||
|
The parser uses traits to determine if the callback is possible.
|
||||||
|
If the Derived type omits the callbacks, they are simply skipped
|
||||||
|
with no compilation error.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
VFALCO TODO is_call_possible, enable_if_t on Derived calls
|
||||||
|
use boost::string_ref instead of std::string
|
||||||
|
*/
|
||||||
|
template<class Derived>
|
||||||
class basic_parser
|
class basic_parser
|
||||||
{
|
{
|
||||||
private:
|
http_parser state_;
|
||||||
// These structures must exactly match the
|
boost::system::error_code* ec_;
|
||||||
// declarations in joyent http_parser.h include
|
|
||||||
//
|
|
||||||
struct state_t
|
|
||||||
{
|
|
||||||
unsigned int type : 2;
|
|
||||||
unsigned int flags : 6;
|
|
||||||
unsigned int state : 8;
|
|
||||||
unsigned int header_state : 8;
|
|
||||||
unsigned int index : 8;
|
|
||||||
std::uint32_t nread;
|
|
||||||
std::uint64_t content_length;
|
|
||||||
unsigned short http_major;
|
|
||||||
unsigned short http_minor;
|
|
||||||
unsigned int status_code : 16;
|
|
||||||
unsigned int method : 8;
|
|
||||||
unsigned int http_errno : 7;
|
|
||||||
unsigned int upgrade : 1;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
using data_cb_t = int (*) (
|
|
||||||
state_t*, const char *at, size_t length);
|
|
||||||
using cb_t = int (*) (state_t*);
|
|
||||||
|
|
||||||
struct hooks_t
|
|
||||||
{
|
|
||||||
cb_t on_message_begin;
|
|
||||||
data_cb_t on_url;
|
|
||||||
data_cb_t on_status;
|
|
||||||
data_cb_t on_header_field;
|
|
||||||
data_cb_t on_header_value;
|
|
||||||
cb_t on_headers_complete;
|
|
||||||
data_cb_t on_body;
|
|
||||||
cb_t on_message_complete;
|
|
||||||
cb_t on_chunk_header;
|
|
||||||
cb_t on_chunk_complete;
|
|
||||||
};
|
|
||||||
|
|
||||||
char state_ [sizeof(state_t)];
|
|
||||||
char hooks_ [sizeof(hooks_t)];
|
|
||||||
|
|
||||||
bool complete_ = false;
|
bool complete_ = false;
|
||||||
std::string url_;
|
std::string url_;
|
||||||
std::string status_;
|
std::string status_;
|
||||||
@@ -90,20 +108,36 @@ private:
|
|||||||
public:
|
public:
|
||||||
using error_code = boost::system::error_code;
|
using error_code = boost::system::error_code;
|
||||||
|
|
||||||
virtual
|
/** Move constructor.
|
||||||
~basic_parser() = default;
|
|
||||||
|
The state of the moved-from object is undefined,
|
||||||
|
but safe to destroy.
|
||||||
|
*/
|
||||||
|
basic_parser(basic_parser&& other);
|
||||||
|
|
||||||
|
/** Move assignment.
|
||||||
|
|
||||||
|
The state of the moved-from object is undefined,
|
||||||
|
but safe to destroy.
|
||||||
|
*/
|
||||||
|
basic_parser&
|
||||||
|
operator=(basic_parser&& other);
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
basic_parser(basic_parser const& other);
|
||||||
|
|
||||||
|
/** Copy assignment. */
|
||||||
|
basic_parser& operator=(basic_parser const& other);
|
||||||
|
|
||||||
/** Construct the parser.
|
/** Construct the parser.
|
||||||
If `request` is `true` this sets up the parser to
|
|
||||||
process an HTTP request.
|
@param request If `true`, the parser is setup for a request.
|
||||||
*/
|
*/
|
||||||
explicit
|
explicit
|
||||||
basic_parser (bool request) noexcept;
|
basic_parser(bool request) noexcept;
|
||||||
|
|
||||||
basic_parser&
|
|
||||||
operator= (basic_parser&& other);
|
|
||||||
|
|
||||||
/** Returns `true` if parsing is complete.
|
/** Returns `true` if parsing is complete.
|
||||||
|
|
||||||
This is only defined when no errors have been returned.
|
This is only defined when no errors have been returned.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
@@ -113,153 +147,406 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Write data to the parser.
|
/** Write data to the parser.
|
||||||
@param data A buffer containing the data to write
|
|
||||||
@param bytes The size of the buffer pointed to by data.
|
|
||||||
@return A pair with bool success, and the number of bytes consumed.
|
|
||||||
*/
|
|
||||||
std::pair <error_code, std::size_t>
|
|
||||||
write (void const* data, std::size_t bytes);
|
|
||||||
|
|
||||||
/** Write a set of buffer data to the parser.
|
@param data A pointer to a buffer representing the input sequence.
|
||||||
The return value includes the error code if any,
|
@param size The number of bytes in the buffer pointed to by data.
|
||||||
and the number of bytes consumed in the input sequence.
|
|
||||||
@param buffers The buffers to write. These must meet the
|
@throws boost::system::system_error Thrown on failure.
|
||||||
requirements of ConstBufferSequence.
|
|
||||||
@return A pair with bool success, and the number of bytes consumed.
|
@return The number of bytes consumed in the input sequence.
|
||||||
*/
|
*/
|
||||||
template <class ConstBufferSequence>
|
std::size_t
|
||||||
std::pair <error_code, std::size_t>
|
write(void const* data, std::size_t size)
|
||||||
write (ConstBufferSequence const& buffers);
|
{
|
||||||
|
error_code ec;
|
||||||
|
auto const used = write(data, size, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write data to the parser.
|
||||||
|
|
||||||
|
@param data A pointer to a buffer representing the input sequence.
|
||||||
|
@param size The number of bytes in the buffer pointed to by data.
|
||||||
|
@param ec Set to the error, if any error occurred.
|
||||||
|
|
||||||
|
@return The number of bytes consumed in the input sequence.
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
write(void const* data, std::size_t size,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
|
/** Write data to the parser.
|
||||||
|
|
||||||
|
@param buffers An object meeting the requirements of
|
||||||
|
ConstBufferSequence that represents the input sequence.
|
||||||
|
|
||||||
|
@throws boost::system::system_error Thrown on failure.
|
||||||
|
|
||||||
|
@return The number of bytes consumed in the input sequence.
|
||||||
|
*/
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write(ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
auto const used = write(buffers, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write data to the parser.
|
||||||
|
|
||||||
|
@param buffers An object meeting the requirements of
|
||||||
|
ConstBufferSequence that represents the input sequence.
|
||||||
|
@param ec Set to the error, if any error occurred.
|
||||||
|
|
||||||
|
@return The number of bytes consumed in the input sequence.
|
||||||
|
*/
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write(ConstBufferSequence const& buffers,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
/** Called to indicate the end of file.
|
/** Called to indicate the end of file.
|
||||||
|
|
||||||
HTTP needs to know where the end of the stream is. For example,
|
HTTP needs to know where the end of the stream is. For example,
|
||||||
sometimes servers send responses without Content-Length and
|
sometimes servers send responses without Content-Length and
|
||||||
expect the client to consume input (for the body) until EOF.
|
expect the client to consume input (for the body) until EOF.
|
||||||
Callbacks and errors will still be processed as usual.
|
Callbacks and errors will still be processed as usual.
|
||||||
|
|
||||||
@note This is typically called when a socket read returns eof.
|
@note This is typically called when a socket read returns eof.
|
||||||
@return `true` if the message is complete.
|
|
||||||
|
@throws boost::system::system_error Thrown on failure.
|
||||||
*/
|
*/
|
||||||
error_code
|
|
||||||
write_eof();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** Called once when a new message begins. */
|
|
||||||
virtual
|
|
||||||
void
|
void
|
||||||
on_start() = 0;
|
write_eof()
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
write_eof(ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
/** Called for each header field. */
|
/** Called to indicate the end of file.
|
||||||
virtual
|
|
||||||
void
|
|
||||||
on_field (std::string const& field, std::string const& value) = 0;
|
|
||||||
|
|
||||||
/** Called for requests when all the headers have been received.
|
HTTP needs to know where the end of the stream is. For example,
|
||||||
This will precede any content body.
|
sometimes servers send responses without Content-Length and
|
||||||
When keep_alive is false:
|
expect the client to consume input (for the body) until EOF.
|
||||||
* Server roles respond with a "Connection: close" header.
|
Callbacks and errors will still be processed as usual.
|
||||||
* Client roles close the connection.
|
|
||||||
When upgrade is true, no content-body is expected, and the
|
|
||||||
return value is ignored.
|
|
||||||
|
|
||||||
@param method The HTTP method specified in the request line
|
@note This is typically called when a socket read returns eof.
|
||||||
@param major The HTTP major version number
|
|
||||||
@param minor The HTTP minor version number
|
@param ec Set to the error, if any error occurred.
|
||||||
@param url The URL specified in the request line
|
|
||||||
@param keep_alive `false` if this is the last message.
|
|
||||||
@param upgrade `true` if the Upgrade header is specified
|
|
||||||
@return `true` If upgrade is false and a content body is expected.
|
|
||||||
*/
|
*/
|
||||||
virtual
|
|
||||||
bool
|
|
||||||
on_request (method_t method, std::string const& url,
|
|
||||||
int major, int minor, bool keep_alive, bool upgrade) = 0;
|
|
||||||
|
|
||||||
/** Called for responses when all the headers have been received.
|
|
||||||
This will precede any content body.
|
|
||||||
When keep_alive is `false`:
|
|
||||||
* Client roles close the connection.
|
|
||||||
* Server roles respond with a "Connection: close" header.
|
|
||||||
When upgrade is true, no content-body is expected, and the
|
|
||||||
return value is ignored.
|
|
||||||
|
|
||||||
@param status The numerical HTTP status code in the response line
|
|
||||||
@param text The status text in the response line
|
|
||||||
@param major The HTTP major version number
|
|
||||||
@param minor The HTTP minor version number
|
|
||||||
@param keep_alive `false` if this is the last message.
|
|
||||||
@param upgrade `true` if the Upgrade header is specified
|
|
||||||
@return `true` If upgrade is false and a content body is expected.
|
|
||||||
*/
|
|
||||||
virtual
|
|
||||||
bool
|
|
||||||
on_response (int status, std::string const& text,
|
|
||||||
int major, int minor, bool keep_alive, bool upgrade) = 0;
|
|
||||||
|
|
||||||
/** Called zero or more times for the content body.
|
|
||||||
Any transfer encoding is already decoded in the
|
|
||||||
memory pointed to by data.
|
|
||||||
|
|
||||||
@param data A memory block containing the next decoded
|
|
||||||
chunk of the content body.
|
|
||||||
@param bytes The number of bytes pointed to by data.
|
|
||||||
*/
|
|
||||||
virtual
|
|
||||||
void
|
void
|
||||||
on_body (void const* data, std::size_t bytes) = 0;
|
write_eof(error_code& ec);
|
||||||
|
|
||||||
/** Called once when the message is complete. */
|
|
||||||
virtual
|
|
||||||
void
|
|
||||||
on_complete() = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void check_header();
|
Derived&
|
||||||
|
impl()
|
||||||
|
{
|
||||||
|
return *static_cast<Derived*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
int do_message_start ();
|
template<class C>
|
||||||
int do_url (char const* in, std::size_t bytes);
|
class has_on_start_t
|
||||||
int do_status (char const* in, std::size_t bytes);
|
{
|
||||||
int do_header_field (char const* in, std::size_t bytes);
|
template<class T, class R =
|
||||||
int do_header_value (char const* in, std::size_t bytes);
|
decltype(std::declval<T>().on_start(), std::true_type{})>
|
||||||
int do_headers_complete ();
|
static R check(int);
|
||||||
int do_body (char const* in, std::size_t bytes);
|
template <class>
|
||||||
int do_message_complete ();
|
static std::false_type check(...);
|
||||||
int do_chunk_header();
|
using type = decltype(check<C>(0));
|
||||||
int do_chunk_complete();
|
public:
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
template<class C>
|
||||||
|
using has_on_start =
|
||||||
|
std::bool_constant<has_on_start_t<C>::value>;
|
||||||
|
|
||||||
static int cb_message_start (joyent::http_parser*);
|
void
|
||||||
static int cb_url (joyent::http_parser*, char const*, std::size_t);
|
call_on_start(std::true_type)
|
||||||
static int cb_status (joyent::http_parser*, char const*, std::size_t);
|
{
|
||||||
static int cb_header_field (joyent::http_parser*, char const*, std::size_t);
|
impl().on_start();
|
||||||
static int cb_header_value (joyent::http_parser*, char const*, std::size_t);
|
}
|
||||||
static int cb_headers_complete (joyent::http_parser*);
|
|
||||||
static int cb_body (joyent::http_parser*, char const*, std::size_t);
|
void
|
||||||
static int cb_message_complete (joyent::http_parser*);
|
call_on_start(std::false_type)
|
||||||
static int cb_chunk_header (joyent::http_parser*);
|
{
|
||||||
static int cb_chunk_complete (joyent::http_parser*);
|
}
|
||||||
|
|
||||||
|
template<class C>
|
||||||
|
class has_on_field_t
|
||||||
|
{
|
||||||
|
template<class T, class R =
|
||||||
|
decltype(std::declval<T>().on_field(
|
||||||
|
std::declval<std::string const&>(),
|
||||||
|
std::declval<std::string const&>()),
|
||||||
|
std::true_type{})>
|
||||||
|
static R check(int);
|
||||||
|
template <class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<C>(0));
|
||||||
|
public:
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
template<class C>
|
||||||
|
using has_on_field =
|
||||||
|
std::bool_constant<has_on_field_t<C>::value>;
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_field(std::string const& field,
|
||||||
|
std::string const& value, std::true_type)
|
||||||
|
{
|
||||||
|
impl().on_field(field, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_field(std::string const&, std::string const&,
|
||||||
|
std::false_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class C>
|
||||||
|
class has_on_headers_complete_t
|
||||||
|
{
|
||||||
|
template<class T, class R =
|
||||||
|
decltype(std::declval<T>().on_headers_complete(
|
||||||
|
std::declval<error_code&>()), std::true_type{})>
|
||||||
|
static R check(int);
|
||||||
|
template <class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<C>(0));
|
||||||
|
public:
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
template<class C>
|
||||||
|
using has_on_headers_complete =
|
||||||
|
std::bool_constant<has_on_headers_complete_t<C>::value>;
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_headers_complete(error_code& ec, std::true_type)
|
||||||
|
{
|
||||||
|
impl().on_headers_complete(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_headers_complete(error_code&, std::false_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class C>
|
||||||
|
class has_on_request_t
|
||||||
|
{
|
||||||
|
template<class T, class R =
|
||||||
|
decltype(std::declval<T>().on_request(
|
||||||
|
std::declval<method_t>(), std::declval<std::string>(),
|
||||||
|
std::declval<int>(), std::declval<int>(),
|
||||||
|
std::declval<bool>(), std::declval<bool>()),
|
||||||
|
std::true_type{})>
|
||||||
|
static R check(int);
|
||||||
|
template <class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<C>(0));
|
||||||
|
public:
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
template<class C>
|
||||||
|
using has_on_request =
|
||||||
|
std::bool_constant<has_on_request_t<C>::value>;
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_request(method_t method, std::string url,
|
||||||
|
int major, int minor, bool keep_alive, bool upgrade,
|
||||||
|
std::true_type)
|
||||||
|
{
|
||||||
|
impl().on_request(
|
||||||
|
method, url, major, minor, keep_alive, upgrade);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_request(method_t, std::string, int, int, bool, bool,
|
||||||
|
std::false_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class C>
|
||||||
|
class has_on_response_t
|
||||||
|
{
|
||||||
|
template<class T, class R =
|
||||||
|
decltype(std::declval<T>().on_response(
|
||||||
|
std::declval<int>(), std::declval<std::string>,
|
||||||
|
std::declval<int>(), std::declval<int>(),
|
||||||
|
std::declval<bool>(), std::declval<bool>()),
|
||||||
|
std::true_type{})>
|
||||||
|
static R check(int);
|
||||||
|
template <class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
#if 0
|
||||||
|
using type = decltype(check<C>(0));
|
||||||
|
#else
|
||||||
|
// VFALCO Trait seems broken for http::parser
|
||||||
|
using type = std::true_type;
|
||||||
|
#endif
|
||||||
|
public:
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
template<class C>
|
||||||
|
using has_on_response =
|
||||||
|
std::bool_constant<has_on_response_t<C>::value>;
|
||||||
|
|
||||||
|
bool
|
||||||
|
call_on_response(int status, std::string text,
|
||||||
|
int major, int minor, bool keep_alive, bool upgrade,
|
||||||
|
std::true_type)
|
||||||
|
{
|
||||||
|
return impl().on_response(
|
||||||
|
status, text, major, minor, keep_alive, upgrade);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
call_on_response(int, std::string, int, int, bool, bool,
|
||||||
|
std::false_type)
|
||||||
|
{
|
||||||
|
// VFALCO Certainly incorrect
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class C>
|
||||||
|
class has_on_body_t
|
||||||
|
{
|
||||||
|
template<class T, class R =
|
||||||
|
decltype(std::declval<T>().on_body(
|
||||||
|
std::declval<void const*>(), std::declval<std::size_t>(),
|
||||||
|
std::declval<error_code&>()), std::true_type{})>
|
||||||
|
static R check(int);
|
||||||
|
template <class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<C>(0));
|
||||||
|
public:
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
template<class C>
|
||||||
|
using has_on_body =
|
||||||
|
std::bool_constant<has_on_body_t<C>::value>;
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_body(void const* data, std::size_t bytes,
|
||||||
|
error_code& ec, std::true_type)
|
||||||
|
{
|
||||||
|
impl().on_body(data, bytes, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_body(void const*, std::size_t,
|
||||||
|
error_code&, std::false_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class C>
|
||||||
|
class has_on_complete_t
|
||||||
|
{
|
||||||
|
template<class T, class R =
|
||||||
|
decltype(std::declval<T>().on_complete(), std::true_type{})>
|
||||||
|
static R check(int);
|
||||||
|
template <class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<C>(0));
|
||||||
|
public:
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
template<class C>
|
||||||
|
using has_on_complete =
|
||||||
|
std::bool_constant<has_on_complete_t<C>::value>;
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_complete(std::true_type)
|
||||||
|
{
|
||||||
|
impl().on_complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
call_on_complete(std::false_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
check_header();
|
||||||
|
|
||||||
|
static int cb_message_start(http_parser*);
|
||||||
|
static int cb_url(http_parser*, char const*, std::size_t);
|
||||||
|
static int cb_status(http_parser*, char const*, std::size_t);
|
||||||
|
static int cb_header_field(http_parser*, char const*, std::size_t);
|
||||||
|
static int cb_header_value(http_parser*, char const*, std::size_t);
|
||||||
|
static int cb_headers_complete(http_parser*);
|
||||||
|
static int cb_body(http_parser*, char const*, std::size_t);
|
||||||
|
static int cb_message_complete(http_parser*);
|
||||||
|
static int cb_chunk_header(http_parser*);
|
||||||
|
static int cb_chunk_complete(http_parser*);
|
||||||
|
|
||||||
|
struct hooks_t : http_parser_settings
|
||||||
|
{
|
||||||
|
hooks_t()
|
||||||
|
{
|
||||||
|
http_parser_settings_init(this);
|
||||||
|
on_message_begin = &basic_parser::cb_message_start;
|
||||||
|
on_url = &basic_parser::cb_url;
|
||||||
|
on_status = &basic_parser::cb_status;
|
||||||
|
on_header_field = &basic_parser::cb_header_field;
|
||||||
|
on_header_value = &basic_parser::cb_header_value;
|
||||||
|
on_headers_complete = &basic_parser::cb_headers_complete;
|
||||||
|
on_body = &basic_parser::cb_body;
|
||||||
|
on_message_complete = &basic_parser::cb_message_complete;
|
||||||
|
on_chunk_header = &basic_parser::cb_chunk_header;
|
||||||
|
on_chunk_complete = &basic_parser::cb_chunk_complete;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
http_parser_settings const*
|
||||||
|
hooks();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ConstBufferSequence>
|
template<class Derived>
|
||||||
auto
|
template<class ConstBufferSequence>
|
||||||
basic_parser::write (ConstBufferSequence const& buffers) ->
|
std::size_t
|
||||||
std::pair <error_code, std::size_t>
|
basic_parser<Derived>::write(
|
||||||
|
ConstBufferSequence const& buffers, error_code& ec)
|
||||||
{
|
{
|
||||||
std::pair <error_code, std::size_t> result ({}, 0);
|
static_assert(beast::is_ConstBufferSequence<
|
||||||
|
ConstBufferSequence>::value,
|
||||||
|
"ConstBufferSequence requirements not met");
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::size_t bytes_used = 0;
|
||||||
for (auto const& buffer : buffers)
|
for (auto const& buffer : buffers)
|
||||||
{
|
{
|
||||||
std::size_t bytes_consumed;
|
auto const n = write(
|
||||||
std::tie (result.first, bytes_consumed) =
|
buffer_cast<void const*>(buffer),
|
||||||
write (boost::asio::buffer_cast <void const*> (buffer),
|
buffer_size(buffer), ec);
|
||||||
boost::asio::buffer_size (buffer));
|
if(ec)
|
||||||
if (result.first)
|
return 0;
|
||||||
break;
|
bytes_used += n;
|
||||||
result.second += bytes_consumed;
|
if(complete())
|
||||||
if (complete())
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return result;
|
return bytes_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
http_parser_settings const*
|
||||||
|
basic_parser<Derived>::hooks()
|
||||||
|
{
|
||||||
|
static hooks_t const h;
|
||||||
|
return &h;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // http
|
} // http
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/http/impl/basic_parser.ipp>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace deprecated_http {
|
||||||
|
|
||||||
/** Container for the HTTP content-body. */
|
/** Container for the HTTP content-body. */
|
||||||
class body
|
class body
|
||||||
@@ -144,7 +144,7 @@ body::data() const
|
|||||||
return buf_->data();
|
return buf_->data();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // http
|
} // deprecated_http
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ chunk_encoded_buffers<Buffers>::to_hex(
|
|||||||
|
|
||||||
template <class Buffers>
|
template <class Buffers>
|
||||||
chunk_encoded_buffers<Buffers>::const_iterator::const_iterator()
|
chunk_encoded_buffers<Buffers>::const_iterator::const_iterator()
|
||||||
: where_(Where::end)
|
: buffers_(nullptr)
|
||||||
, buffers_(nullptr)
|
, where_(Where::end)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ chunk_encoded_buffers<Buffers>::const_iterator::operator--() ->
|
|||||||
const_iterator&
|
const_iterator&
|
||||||
{
|
{
|
||||||
assert(buffers_);
|
assert(buffers_);
|
||||||
assert(where_ != Where::begin);
|
assert(where_ != Where::head);
|
||||||
if (where_ == Where::end)
|
if (where_ == Where::end)
|
||||||
where_ = Where::input;
|
where_ = Where::input;
|
||||||
else if (iter_ != buffers_->buffers_.begin())
|
else if (iter_ != buffers_->buffers_.begin())
|
||||||
@@ -247,37 +247,44 @@ chunk_encoded_buffers<Buffers>::const_iterator::const_iterator(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // detail
|
||||||
|
|
||||||
/** Returns a chunk-encoded BufferSequence.
|
/** Returns a chunk-encoded BufferSequence.
|
||||||
|
|
||||||
See:
|
See:
|
||||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
|
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
|
||||||
|
|
||||||
@tparam Buffers A type meeting the requirements of BufferSequence.
|
|
||||||
@param buffers The input buffer sequence.
|
@param buffers The input buffer sequence.
|
||||||
|
|
||||||
@param final_chunk `true` If this should include a final-chunk.
|
@param final_chunk `true` If this should include a final-chunk.
|
||||||
@return A chunk-encoded ConstBufferSeqeunce representing the input.
|
|
||||||
|
@return A chunk-encoded ConstBufferSequence representing the input.
|
||||||
*/
|
*/
|
||||||
/** @{ */
|
template<class ConstBufferSequence>
|
||||||
template <class Buffers>
|
#if GENERATING_DOCS
|
||||||
detail::chunk_encoded_buffers<Buffers>
|
implementation_defined
|
||||||
chunk_encode (Buffers const& buffers,
|
#else
|
||||||
|
detail::chunk_encoded_buffers<ConstBufferSequence>
|
||||||
|
#endif
|
||||||
|
chunk_encode(ConstBufferSequence const& buffers,
|
||||||
bool final_chunk = false)
|
bool final_chunk = false)
|
||||||
{
|
{
|
||||||
return detail::chunk_encoded_buffers<
|
return detail::chunk_encoded_buffers<
|
||||||
Buffers>(buffers, final_chunk);
|
ConstBufferSequence>{buffers, final_chunk};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a chunked encoding final chunk.
|
/// Returns a chunked encoding final chunk.
|
||||||
inline
|
inline
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
implementation_defined
|
||||||
|
#else
|
||||||
boost::asio::const_buffers_1
|
boost::asio::const_buffers_1
|
||||||
|
#endif
|
||||||
chunk_encode_final()
|
chunk_encode_final()
|
||||||
{
|
{
|
||||||
return boost::asio::const_buffers_1(
|
return boost::asio::const_buffers_1(
|
||||||
"0\r\n\r\n", 5);
|
"0\r\n\r\n", 5);
|
||||||
}
|
}
|
||||||
/** @} */
|
|
||||||
|
|
||||||
} // http
|
} // http
|
||||||
} // beast
|
} // beast
|
||||||
|
|||||||
83
src/beast/beast/http/detail/error.h
Normal file
83
src/beast/beast/http/detail/error.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_DETAIL_ERROR_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_DETAIL_ERROR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/src/nodejs_parser.h>
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class message_category
|
||||||
|
: public boost::system::error_category
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const char*
|
||||||
|
name() const noexcept override
|
||||||
|
{
|
||||||
|
return "http error";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
message(int ev) const override
|
||||||
|
{
|
||||||
|
return http_errno_description(
|
||||||
|
static_cast<http_errno>(ev));
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::system::error_condition
|
||||||
|
default_error_condition(int ev) const noexcept override
|
||||||
|
{
|
||||||
|
return boost::system::error_condition{ev, *this};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
equivalent(int ev,
|
||||||
|
boost::system::error_condition const& condition
|
||||||
|
) const noexcept override
|
||||||
|
{
|
||||||
|
return condition.value() == ev &&
|
||||||
|
&condition.category() == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
equivalent(boost::system::error_code const& error,
|
||||||
|
int ev) const noexcept override
|
||||||
|
{
|
||||||
|
return error.value() == ev &&
|
||||||
|
&error.category() == this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class = void>
|
||||||
|
auto
|
||||||
|
make_error(int http_errno)
|
||||||
|
{
|
||||||
|
static message_category const mc{};
|
||||||
|
return boost::system::error_code{http_errno, mc};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
133
src/beast/beast/http/detail/write_preparation.h
Normal file
133
src/beast/beast/http/detail/write_preparation.h
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_WRITE_PREPARATION_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_WRITE_PREPARATION_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/asio/streambuf.h>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class has_content_length_value
|
||||||
|
{
|
||||||
|
template<class U, class R = typename std::is_convertible<
|
||||||
|
decltype(std::declval<U>().content_length()),
|
||||||
|
std::size_t>>
|
||||||
|
static R check(int);
|
||||||
|
template <class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<T>(0));
|
||||||
|
public:
|
||||||
|
// `true` if `T` meets the requirements.
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determines if the writer can provide the content length
|
||||||
|
template<class T>
|
||||||
|
using has_content_length =
|
||||||
|
std::integral_constant<bool,
|
||||||
|
has_content_length_value<T>::value>;
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
struct write_preparation
|
||||||
|
{
|
||||||
|
using headers_type =
|
||||||
|
basic_headers<std::allocator<char>>;
|
||||||
|
|
||||||
|
message<isRequest, Body, Headers> const& msg;
|
||||||
|
typename Body::writer w;
|
||||||
|
streambuf sb;
|
||||||
|
bool chunked;
|
||||||
|
bool close;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
write_preparation(
|
||||||
|
message<isRequest, Body, Headers> const& msg_)
|
||||||
|
: msg(msg_)
|
||||||
|
, w(msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
init(error_code& ec)
|
||||||
|
{
|
||||||
|
w.init(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
// VFALCO TODO This implementation requires making a
|
||||||
|
// copy of the headers, we can do better.
|
||||||
|
// VFALCO Should we be using handler_alloc?
|
||||||
|
headers_type h(msg.headers.begin(), msg.headers.end());
|
||||||
|
set_content_length(h, has_content_length<
|
||||||
|
typename Body::writer>{});
|
||||||
|
|
||||||
|
// VFALCO TODO Keep-Alive
|
||||||
|
|
||||||
|
if(close)
|
||||||
|
{
|
||||||
|
if(msg.version >= 11)
|
||||||
|
h.insert("Connection", "close");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(msg.version < 11)
|
||||||
|
h.insert("Connection", "keep-alive");
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.write_firstline(sb);
|
||||||
|
write_fields(sb, h);
|
||||||
|
detail::write(sb, "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
set_content_length(headers_type& h,
|
||||||
|
std::true_type)
|
||||||
|
{
|
||||||
|
close = false;
|
||||||
|
chunked = false;
|
||||||
|
h.insert("Content-Length", w.content_length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_content_length(headers_type& h,
|
||||||
|
std::false_type)
|
||||||
|
{
|
||||||
|
if(msg.version >= 11)
|
||||||
|
{
|
||||||
|
close = false;
|
||||||
|
chunked = true;
|
||||||
|
h.insert("Transfer-Encoding", "chunked");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close = true;
|
||||||
|
chunked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
76
src/beast/beast/http/detail/writes.h
Normal file
76
src/beast/beast/http/detail/writes.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_WRITES_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_WRITES_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <boost/utility/string_ref.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class Streambuf, class T,
|
||||||
|
class = std::enable_if_t<is_Streambuf<Streambuf>::value>>
|
||||||
|
void
|
||||||
|
write(Streambuf& streambuf, T&& t)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
auto const& s =
|
||||||
|
boost::lexical_cast<std::string>(
|
||||||
|
std::forward<T>(t));
|
||||||
|
streambuf.commit(buffer_copy(
|
||||||
|
streambuf.prepare(s.size()), buffer(s)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Streambuf, std::size_t N,
|
||||||
|
class = std::enable_if_t< (N>0) &&
|
||||||
|
is_Streambuf<Streambuf>::value>>
|
||||||
|
void
|
||||||
|
write(Streambuf& streambuf, char const(&s)[N])
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
streambuf.commit(buffer_copy(
|
||||||
|
streambuf.prepare(N), buffer(s, N-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Streambuf,
|
||||||
|
class = std::enable_if_t<is_Streambuf<Streambuf>::value>>
|
||||||
|
void
|
||||||
|
write(Streambuf& streambuf, boost::string_ref const& s)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
streambuf.commit(buffer_copy(
|
||||||
|
streambuf.prepare(s.size()),
|
||||||
|
buffer(s.data(), s.size())));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
87
src/beast/beast/http/empty_body.h
Normal file
87
src/beast/beast/http/empty_body.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_EMPTY_BODY_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_EMPTY_BODY_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/error.h>
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <beast/asio/streambuf.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/** An empty content-body.
|
||||||
|
*/
|
||||||
|
struct empty_body
|
||||||
|
{
|
||||||
|
struct value_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reader
|
||||||
|
{
|
||||||
|
template<bool isRequest, class Allocator>
|
||||||
|
explicit
|
||||||
|
reader(message<isRequest, empty_body, Allocator>&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
write(void const*, std::size_t, error_code&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct writer
|
||||||
|
{
|
||||||
|
template<bool isRequest, class Allocator>
|
||||||
|
explicit
|
||||||
|
writer(message<isRequest, empty_body, Allocator> const& m)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
init(error_code& ec)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
content_length() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Write>
|
||||||
|
boost::tribool
|
||||||
|
operator()(resume_context&&, error_code&, Write&& write)
|
||||||
|
{
|
||||||
|
write(boost::asio::null_buffers{});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -17,18 +17,17 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#if BEAST_INCLUDE_BEASTCONFIG
|
#ifndef BEAST_HTTP_ERROR_H_INCLUDED
|
||||||
#include <BeastConfig.h>
|
#define BEAST_HTTP_ERROR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
using error_code = boost::system::error_code;
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <beast/http/impl/basic_parser.cpp>
|
|
||||||
#include <beast/http/impl/joyent_parser.cpp>
|
|
||||||
#include <beast/http/impl/method.cpp>
|
|
||||||
#include <beast/http/impl/URL.cpp>
|
|
||||||
|
|
||||||
#include <beast/http/tests/chunked_encoder.test.cpp>
|
|
||||||
#include <beast/http/tests/parser.test.cpp>
|
|
||||||
#include <beast/http/tests/rfc2616.test.cpp>
|
|
||||||
#include <beast/http/tests/URL.test.cpp>
|
|
||||||
#include <beast/http/tests/urls_large_data.cpp>
|
|
||||||
|
|
||||||
133
src/beast/beast/http/fields.h
Normal file
133
src/beast/beast/http/fields.h
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_FIELDS_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_FIELDS_H_INCLUDED
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-braces"
|
||||||
|
#endif // defined(__clang__)
|
||||||
|
|
||||||
|
template<class = void>
|
||||||
|
auto const&
|
||||||
|
common_fields()
|
||||||
|
{
|
||||||
|
// Must be sorted
|
||||||
|
static std::array<char const*, 82> constexpr h{
|
||||||
|
"Accept"
|
||||||
|
,"Accept-Charset"
|
||||||
|
,"Accept-Datetime"
|
||||||
|
,"Accept-Encoding"
|
||||||
|
,"Accept-Language"
|
||||||
|
,"Accept-Ranges"
|
||||||
|
,"Access-Control-Allow-Credentials"
|
||||||
|
,"Access-Control-Allow-Headers"
|
||||||
|
,"Access-Control-Allow-Methods"
|
||||||
|
,"Access-Control-Allow-Origin"
|
||||||
|
,"Access-Control-Expose-Headers"
|
||||||
|
,"Access-Control-Max-Age"
|
||||||
|
,"Access-Control-Request-Headers"
|
||||||
|
,"Access-Control-Request-Method"
|
||||||
|
,"Age"
|
||||||
|
,"Allow"
|
||||||
|
,"Authorization"
|
||||||
|
,"Cache-Control"
|
||||||
|
,"Connection"
|
||||||
|
,"Content-Disposition"
|
||||||
|
,"Content-Encoding"
|
||||||
|
,"Content-Language"
|
||||||
|
,"Content-Length"
|
||||||
|
,"Content-Location"
|
||||||
|
,"Content-MD5"
|
||||||
|
,"Content-Range"
|
||||||
|
,"Content-Type"
|
||||||
|
,"Cookie"
|
||||||
|
,"DNT"
|
||||||
|
,"Date"
|
||||||
|
,"ETag"
|
||||||
|
,"Expect"
|
||||||
|
,"Expires"
|
||||||
|
,"From"
|
||||||
|
,"Front-End-Https"
|
||||||
|
,"Host"
|
||||||
|
,"If-Match"
|
||||||
|
,"If-Modified-Since"
|
||||||
|
,"If-None-Match"
|
||||||
|
,"If-Range"
|
||||||
|
,"If-Unmodified-Since"
|
||||||
|
,"Keep-Alive"
|
||||||
|
,"Last-Modified"
|
||||||
|
,"Link"
|
||||||
|
,"Location"
|
||||||
|
,"Max-Forwards"
|
||||||
|
,"Origin"
|
||||||
|
,"P3P"
|
||||||
|
,"Pragma"
|
||||||
|
,"Proxy-Authenticate"
|
||||||
|
,"Proxy-Authorization"
|
||||||
|
,"Proxy-Connection"
|
||||||
|
,"Range"
|
||||||
|
,"Referer"
|
||||||
|
,"Refresh"
|
||||||
|
,"Retry-After"
|
||||||
|
,"Server"
|
||||||
|
,"Set-Cookie"
|
||||||
|
,"Strict-Transport-Security"
|
||||||
|
,"TE"
|
||||||
|
,"Timestamp"
|
||||||
|
,"Trailer"
|
||||||
|
,"Transfer-Encoding"
|
||||||
|
,"Upgrade"
|
||||||
|
,"User-Agent"
|
||||||
|
,"VIP"
|
||||||
|
,"Vary"
|
||||||
|
,"Via"
|
||||||
|
,"WWW-Authenticate"
|
||||||
|
,"Warning"
|
||||||
|
,"X-Accel-Redirect"
|
||||||
|
,"X-Content-Security-Policy-Report-Only"
|
||||||
|
,"X-Content-Type-Options"
|
||||||
|
,"X-Forwarded-For"
|
||||||
|
,"X-Forwarded-Proto"
|
||||||
|
,"X-Frame-Options"
|
||||||
|
,"X-Powered-By"
|
||||||
|
,"X-Real-IP"
|
||||||
|
,"X-Requested-With"
|
||||||
|
,"X-UA-Compatible"
|
||||||
|
,"X-Wap-Profile"
|
||||||
|
,"X-XSS-Protection"
|
||||||
|
};
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif // defined(__clang__)
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,390 +20,17 @@
|
|||||||
#ifndef BEAST_HTTP_HEADERS_H_INCLUDED
|
#ifndef BEAST_HTTP_HEADERS_H_INCLUDED
|
||||||
#define BEAST_HTTP_HEADERS_H_INCLUDED
|
#define BEAST_HTTP_HEADERS_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/ci_char_traits.h>
|
#include <beast/http/basic_headers.h>
|
||||||
#include <boost/intrusive/list.hpp>
|
#include <memory>
|
||||||
#include <boost/intrusive/set.hpp>
|
|
||||||
#include <boost/iterator/transform_iterator.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cctype>
|
|
||||||
#include <map>
|
|
||||||
#include <ostream>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
/** Holds a collection of HTTP headers. */
|
template<class Allocator>
|
||||||
class headers
|
using headers = basic_headers<Allocator>;
|
||||||
{
|
|
||||||
public:
|
|
||||||
using value_type = std::pair<std::string, std::string>;
|
|
||||||
|
|
||||||
private:
|
using http_headers =
|
||||||
struct element
|
basic_headers<std::allocator<char>>;
|
||||||
: boost::intrusive::set_base_hook <
|
|
||||||
boost::intrusive::link_mode <
|
|
||||||
boost::intrusive::normal_link>>
|
|
||||||
, boost::intrusive::list_base_hook <
|
|
||||||
boost::intrusive::link_mode <
|
|
||||||
boost::intrusive::normal_link>>
|
|
||||||
{
|
|
||||||
template <class = void>
|
|
||||||
element (std::string const& f, std::string const& v);
|
|
||||||
|
|
||||||
value_type data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct less : private beast::ci_less
|
|
||||||
{
|
|
||||||
template <class String>
|
|
||||||
bool
|
|
||||||
operator() (String const& lhs, element const& rhs) const;
|
|
||||||
|
|
||||||
template <class String>
|
|
||||||
bool
|
|
||||||
operator() (element const& lhs, String const& rhs) const;
|
|
||||||
|
|
||||||
bool
|
|
||||||
operator() (element const& lhs, element const& rhs) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct transform
|
|
||||||
: public std::unary_function <element, value_type>
|
|
||||||
{
|
|
||||||
value_type const&
|
|
||||||
operator() (element const& e) const
|
|
||||||
{
|
|
||||||
return e.data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using list_t = boost::intrusive::make_list <element,
|
|
||||||
boost::intrusive::constant_time_size <false>
|
|
||||||
>::type;
|
|
||||||
|
|
||||||
using set_t = boost::intrusive::make_set <element,
|
|
||||||
boost::intrusive::constant_time_size <true>,
|
|
||||||
boost::intrusive::compare<less>
|
|
||||||
>::type;
|
|
||||||
|
|
||||||
list_t list_;
|
|
||||||
set_t set_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator = boost::transform_iterator <transform,
|
|
||||||
list_t::const_iterator>;
|
|
||||||
using const_iterator = iterator;
|
|
||||||
|
|
||||||
~headers()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
headers() = default;
|
|
||||||
|
|
||||||
headers (headers&& other);
|
|
||||||
headers& operator= (headers&& other);
|
|
||||||
|
|
||||||
headers (headers const& other);
|
|
||||||
headers& operator= (headers const& other);
|
|
||||||
|
|
||||||
/** Returns an iterator to headers in order of appearance. */
|
|
||||||
/** @{ */
|
|
||||||
iterator
|
|
||||||
begin() const;
|
|
||||||
|
|
||||||
iterator
|
|
||||||
end() const;
|
|
||||||
|
|
||||||
iterator
|
|
||||||
cbegin() const;
|
|
||||||
|
|
||||||
iterator
|
|
||||||
cend() const;
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/** Returns an iterator to the case-insensitive matching header. */
|
|
||||||
template <class = void>
|
|
||||||
iterator
|
|
||||||
find (std::string const& field) const;
|
|
||||||
|
|
||||||
/** Returns the value for a case-insensitive matching header, or "" */
|
|
||||||
template <class = void>
|
|
||||||
std::string const&
|
|
||||||
operator[] (std::string const& field) const;
|
|
||||||
|
|
||||||
/** Clear the contents of the headers. */
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
clear() noexcept;
|
|
||||||
|
|
||||||
/** Remove a field.
|
|
||||||
@return The number of fields removed.
|
|
||||||
*/
|
|
||||||
template <class = void>
|
|
||||||
std::size_t
|
|
||||||
erase (std::string const& field);
|
|
||||||
|
|
||||||
/** Append a field value.
|
|
||||||
If a field value already exists the new value will be
|
|
||||||
extended as per RFC2616 Section 4.2.
|
|
||||||
*/
|
|
||||||
// VFALCO TODO Consider allowing rvalue references for std::move
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
append (std::string const& field, std::string const& value);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class = void>
|
|
||||||
std::string
|
|
||||||
to_string (headers const& h);
|
|
||||||
|
|
||||||
// HACK!
|
|
||||||
template <class = void>
|
|
||||||
std::map <std::string, std::string>
|
|
||||||
build_map (headers const& h);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
headers::element::element (
|
|
||||||
std::string const& f, std::string const& v)
|
|
||||||
{
|
|
||||||
data.first = f;
|
|
||||||
data.second = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class String>
|
|
||||||
bool
|
|
||||||
headers::less::operator() (
|
|
||||||
String const& lhs, element const& rhs) const
|
|
||||||
{
|
|
||||||
return beast::ci_less::operator() (lhs, rhs.data.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class String>
|
|
||||||
bool
|
|
||||||
headers::less::operator() (
|
|
||||||
element const& lhs, String const& rhs) const
|
|
||||||
{
|
|
||||||
return beast::ci_less::operator() (lhs.data.first, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
bool
|
|
||||||
headers::less::operator() (
|
|
||||||
element const& lhs, element const& rhs) const
|
|
||||||
{
|
|
||||||
return beast::ci_less::operator() (lhs.data.first, rhs.data.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
inline
|
|
||||||
headers::headers (headers&& other)
|
|
||||||
: list_ (std::move (other.list_))
|
|
||||||
, set_ (std::move (other.set_))
|
|
||||||
{
|
|
||||||
other.list_.clear();
|
|
||||||
other.set_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
headers&
|
|
||||||
headers::operator= (headers&& other)
|
|
||||||
{
|
|
||||||
list_ = std::move(other.list_);
|
|
||||||
set_ = std::move(other.set_);
|
|
||||||
other.list_.clear();
|
|
||||||
other.set_.clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
headers::headers (headers const& other)
|
|
||||||
{
|
|
||||||
for (auto const& e : other.list_)
|
|
||||||
append (e.data.first, e.data.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
headers&
|
|
||||||
headers::operator= (headers const& other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
for (auto const& e : other.list_)
|
|
||||||
append (e.data.first, e.data.second);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
headers::iterator
|
|
||||||
headers::begin() const
|
|
||||||
{
|
|
||||||
return {list_.cbegin(), transform{}};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
headers::iterator
|
|
||||||
headers::end() const
|
|
||||||
{
|
|
||||||
return {list_.cend(), transform{}};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
headers::iterator
|
|
||||||
headers::cbegin() const
|
|
||||||
{
|
|
||||||
return {list_.cbegin(), transform{}};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
headers::iterator
|
|
||||||
headers::cend() const
|
|
||||||
{
|
|
||||||
return {list_.cend(), transform{}};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
headers::iterator
|
|
||||||
headers::find (std::string const& field) const
|
|
||||||
{
|
|
||||||
auto const iter (set_.find (field, less{}));
|
|
||||||
if (iter == set_.end())
|
|
||||||
return {list_.end(), transform{}};
|
|
||||||
return {list_.iterator_to (*iter), transform{}};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
std::string const&
|
|
||||||
headers::operator[] (std::string const& field) const
|
|
||||||
{
|
|
||||||
static std::string none;
|
|
||||||
auto const found (find (field));
|
|
||||||
if (found == end())
|
|
||||||
return none;
|
|
||||||
return found->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
void
|
|
||||||
headers::clear() noexcept
|
|
||||||
{
|
|
||||||
for (auto iter (list_.begin()); iter != list_.end();)
|
|
||||||
delete &(*iter++);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
std::size_t
|
|
||||||
headers::erase (std::string const& field)
|
|
||||||
{
|
|
||||||
auto const iter = set_.find(field, less{});
|
|
||||||
if (iter == set_.end())
|
|
||||||
return 0;
|
|
||||||
element& e = *iter;
|
|
||||||
set_.erase(set_.iterator_to(e));
|
|
||||||
list_.erase(list_.iterator_to(e));
|
|
||||||
delete &e;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
void
|
|
||||||
headers::append (std::string const& field,
|
|
||||||
std::string const& value)
|
|
||||||
{
|
|
||||||
set_t::insert_commit_data d;
|
|
||||||
auto const result (set_.insert_check (field, less{}, d));
|
|
||||||
if (result.second)
|
|
||||||
{
|
|
||||||
element* const p = new element (field, value);
|
|
||||||
list_.push_back (*p);
|
|
||||||
set_.insert_commit (*p, d);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If field already exists, append comma
|
|
||||||
// separated value as per RFC2616 section 4.2
|
|
||||||
auto& cur (result.first->data.second);
|
|
||||||
cur.reserve (cur.size() + 1 + value.size());
|
|
||||||
cur.append (1, ',');
|
|
||||||
cur.append (value);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template <class Streambuf>
|
|
||||||
void
|
|
||||||
write (Streambuf& stream, std::string const& s)
|
|
||||||
{
|
|
||||||
stream.commit (boost::asio::buffer_copy (
|
|
||||||
stream.prepare (s.size()), boost::asio::buffer(s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Streambuf>
|
|
||||||
void
|
|
||||||
write (Streambuf& stream, char const* s)
|
|
||||||
{
|
|
||||||
auto const len (::strlen(s));
|
|
||||||
stream.commit (boost::asio::buffer_copy (
|
|
||||||
stream.prepare (len), boost::asio::buffer (s, len)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Streambuf>
|
|
||||||
void
|
|
||||||
write (Streambuf& stream, headers const& h)
|
|
||||||
{
|
|
||||||
for (auto const& _ : h)
|
|
||||||
{
|
|
||||||
write (stream, _.first);
|
|
||||||
write (stream, ": ");
|
|
||||||
write (stream, _.second);
|
|
||||||
write (stream, "\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
std::string
|
|
||||||
to_string (headers const& h)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
std::size_t n (0);
|
|
||||||
for (auto const& e : h)
|
|
||||||
n += e.first.size() + 2 + e.second.size() + 2;
|
|
||||||
s.reserve (n);
|
|
||||||
for (auto const& e : h)
|
|
||||||
{
|
|
||||||
s.append (e.first);
|
|
||||||
s.append (": ");
|
|
||||||
s.append (e.second);
|
|
||||||
s.append ("\r\n");
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
std::ostream&
|
|
||||||
operator<< (std::ostream& s, headers const& h)
|
|
||||||
{
|
|
||||||
s << to_string(h);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
std::map <std::string, std::string>
|
|
||||||
build_map (headers const& h)
|
|
||||||
{
|
|
||||||
std::map <std::string, std::string> c;
|
|
||||||
for (auto const& e : h)
|
|
||||||
{
|
|
||||||
auto key (e.first);
|
|
||||||
// TODO Replace with safe C++14 version
|
|
||||||
std::transform (key.begin(), key.end(), key.begin(), ::tolower);
|
|
||||||
c [key] = e.second;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // http
|
} // http
|
||||||
} // beast
|
} // beast
|
||||||
|
|||||||
312
src/beast/beast/http/impl/basic_headers.ipp
Normal file
312
src/beast/beast/http/impl/basic_headers.ipp
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_BASIC_HEADERS_IPP_INCLUDED
|
||||||
|
#define BEAST_HTTP_BASIC_HEADERS_IPP_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/detail/writes.h>
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
basic_headers_base::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return list_.cbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
basic_headers_base::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return list_.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
basic_headers_base::cbegin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return list_.cbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
basic_headers_base::cend() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return list_.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
delete_all()
|
||||||
|
{
|
||||||
|
for(auto it = list_.begin(); it != list_.end();)
|
||||||
|
{
|
||||||
|
auto& e = *it++;
|
||||||
|
e.~element();
|
||||||
|
alloc_traits::deallocate(
|
||||||
|
this->member(), &e, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
move_assign(basic_headers& other, std::false_type)
|
||||||
|
{
|
||||||
|
if(this->member() != other.member())
|
||||||
|
{
|
||||||
|
copy_from(other);
|
||||||
|
other.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_ = std::move(other.set_);
|
||||||
|
list_ = std::move(other.list_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
move_assign(basic_headers& other, std::true_type)
|
||||||
|
{
|
||||||
|
this->member() = std::move(other.member());
|
||||||
|
set_ = std::move(other.set_);
|
||||||
|
list_ = std::move(other.list_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
copy_assign(basic_headers const& other, std::false_type)
|
||||||
|
{
|
||||||
|
copy_from(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
copy_assign(basic_headers const& other, std::true_type)
|
||||||
|
{
|
||||||
|
this->member() = other.member();
|
||||||
|
copy_from(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
~basic_headers()
|
||||||
|
{
|
||||||
|
delete_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
basic_headers(Allocator const& alloc)
|
||||||
|
: empty_base_optimization<
|
||||||
|
alloc_type>(alloc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
basic_headers(basic_headers&& other)
|
||||||
|
: empty_base_optimization<alloc_type>(
|
||||||
|
std::move(other.member()))
|
||||||
|
, detail::basic_headers_base(
|
||||||
|
std::move(other.set_), std::move(other.list_))
|
||||||
|
{
|
||||||
|
other.list_.clear();
|
||||||
|
other.set_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
operator=(basic_headers&& other) ->
|
||||||
|
basic_headers&
|
||||||
|
{
|
||||||
|
if(this == &other)
|
||||||
|
return *this;
|
||||||
|
clear();
|
||||||
|
move_assign(other, std::integral_constant<bool,
|
||||||
|
alloc_traits::propagate_on_container_move_assignment::value>{});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
basic_headers(basic_headers const& other)
|
||||||
|
: basic_headers(alloc_traits::
|
||||||
|
select_on_container_copy_construction(other.member()))
|
||||||
|
{
|
||||||
|
copy_from(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
operator=(basic_headers const& other) ->
|
||||||
|
basic_headers&
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
copy_assign(other, std::integral_constant<bool,
|
||||||
|
alloc_traits::propagate_on_container_copy_assignment::value>{});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
basic_headers(basic_headers<OtherAlloc> const& other)
|
||||||
|
{
|
||||||
|
copy_from(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
template<class OtherAlloc>
|
||||||
|
auto
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
operator=(basic_headers<OtherAlloc> const& other) ->
|
||||||
|
basic_headers&
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
copy_from(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
template<class FwdIt>
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
basic_headers(FwdIt first, FwdIt last)
|
||||||
|
{
|
||||||
|
for(;first != last; ++first)
|
||||||
|
insert(first->name(), first->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
find(boost::string_ref const& name) const ->
|
||||||
|
iterator
|
||||||
|
{
|
||||||
|
auto const it = set_.find(name, less{});
|
||||||
|
if(it == set_.end())
|
||||||
|
return list_.end();
|
||||||
|
return list_.iterator_to(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
boost::string_ref
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
operator[](boost::string_ref const& name) const
|
||||||
|
{
|
||||||
|
// VFALCO This none object looks sketchy
|
||||||
|
static boost::string_ref const none;
|
||||||
|
auto const it = find(name);
|
||||||
|
if(it == end())
|
||||||
|
return none;
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
clear() noexcept
|
||||||
|
{
|
||||||
|
delete_all();
|
||||||
|
list_.clear();
|
||||||
|
set_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
std::size_t
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
erase(boost::string_ref const& name)
|
||||||
|
{
|
||||||
|
auto const it = set_.find(name, less{});
|
||||||
|
if(it == set_.end())
|
||||||
|
return 0;
|
||||||
|
auto& e = *it;
|
||||||
|
set_.erase(set_.iterator_to(e));
|
||||||
|
list_.erase(list_.iterator_to(e));
|
||||||
|
alloc_traits::deallocate(this->member(), &e, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
insert(boost::string_ref const& name,
|
||||||
|
boost::string_ref const& value)
|
||||||
|
{
|
||||||
|
typename set_t::insert_commit_data d;
|
||||||
|
auto const result =
|
||||||
|
set_.insert_check(name, less{}, d);
|
||||||
|
if (result.second)
|
||||||
|
{
|
||||||
|
auto const p = alloc_traits::allocate(
|
||||||
|
this->member(), 1);
|
||||||
|
alloc_traits::construct(
|
||||||
|
this->member(), p, name, value);
|
||||||
|
list_.push_back(*p);
|
||||||
|
set_.insert_commit(*p, d);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If field already exists, insert comma
|
||||||
|
// separated value as per RFC2616 section 4.2
|
||||||
|
auto& cur = result.first->data.second;
|
||||||
|
cur.reserve(cur.size() + 1 + value.size());
|
||||||
|
cur.append(1, ',');
|
||||||
|
cur.append(value.data(), value.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
replace(boost::string_ref const& name,
|
||||||
|
boost::string_ref const& value)
|
||||||
|
{
|
||||||
|
erase(name);
|
||||||
|
insert(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,327 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <beast/http/basic_parser.h>
|
|
||||||
#include <beast/http/impl/joyent_parser.h>
|
|
||||||
#include <beast/http/rfc2616.h>
|
|
||||||
#include <boost/system/error_code.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
|
|
||||||
boost::system::error_category const&
|
|
||||||
message_category() noexcept
|
|
||||||
{
|
|
||||||
class message_category_t : public boost::system::error_category
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
const char*
|
|
||||||
name() const noexcept override
|
|
||||||
{
|
|
||||||
return "http::message";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
message (int ev) const override
|
|
||||||
{
|
|
||||||
return joyent::http_errno_description (
|
|
||||||
static_cast<joyent::http_errno>(ev));
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::system::error_condition
|
|
||||||
default_error_condition (int ev) const noexcept override
|
|
||||||
{
|
|
||||||
return boost::system::error_condition (ev, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
equivalent (int ev, boost::system::error_condition const& condition
|
|
||||||
) const noexcept override
|
|
||||||
{
|
|
||||||
return condition.value() == ev &&
|
|
||||||
&condition.category() == this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
equivalent (boost::system::error_code const& error,
|
|
||||||
int ev) const noexcept override
|
|
||||||
{
|
|
||||||
return error.value() == ev &&
|
|
||||||
&error.category() == this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static message_category_t cat;
|
|
||||||
return cat;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
basic_parser::basic_parser (bool request) noexcept
|
|
||||||
{
|
|
||||||
static_assert (sizeof(joyent::http_parser) == sizeof(state_t),
|
|
||||||
"state_t size must match http_parser size");
|
|
||||||
|
|
||||||
static_assert (sizeof(joyent::http_parser_settings) == sizeof(hooks_t),
|
|
||||||
"hooks_t size must match http_parser_settings size");
|
|
||||||
|
|
||||||
auto s (reinterpret_cast <joyent::http_parser*> (&state_));
|
|
||||||
s->data = this;
|
|
||||||
|
|
||||||
auto h (reinterpret_cast <joyent::http_parser_settings*> (&hooks_));
|
|
||||||
h->on_message_begin = &basic_parser::cb_message_start;
|
|
||||||
h->on_url = &basic_parser::cb_url;
|
|
||||||
h->on_status = &basic_parser::cb_status;
|
|
||||||
h->on_header_field = &basic_parser::cb_header_field;
|
|
||||||
h->on_header_value = &basic_parser::cb_header_value;
|
|
||||||
h->on_headers_complete = &basic_parser::cb_headers_complete;
|
|
||||||
h->on_body = &basic_parser::cb_body;
|
|
||||||
h->on_message_complete = &basic_parser::cb_message_complete;
|
|
||||||
h->on_chunk_header = &basic_parser::cb_chunk_header;
|
|
||||||
h->on_chunk_complete = &basic_parser::cb_chunk_complete;
|
|
||||||
|
|
||||||
joyent::http_parser_init (s, request
|
|
||||||
? joyent::http_parser_type::HTTP_REQUEST
|
|
||||||
: joyent::http_parser_type::HTTP_RESPONSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
basic_parser&
|
|
||||||
basic_parser::operator= (basic_parser&& other)
|
|
||||||
{
|
|
||||||
*reinterpret_cast<joyent::http_parser*>(&state_) =
|
|
||||||
*reinterpret_cast<joyent::http_parser*>(&other.state_);
|
|
||||||
reinterpret_cast<joyent::http_parser*>(&state_)->data = this;
|
|
||||||
complete_ = other.complete_;
|
|
||||||
url_ = std::move (other.url_);
|
|
||||||
status_ = std::move (other.status_);
|
|
||||||
field_ = std::move (other.field_);
|
|
||||||
value_ = std::move (other.value_);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto
|
|
||||||
basic_parser::write (void const* data, std::size_t bytes) ->
|
|
||||||
std::pair <error_code, std::size_t>
|
|
||||||
{
|
|
||||||
std::pair <error_code, std::size_t> result ({}, 0);
|
|
||||||
auto s (reinterpret_cast <joyent::http_parser*> (&state_));
|
|
||||||
auto h (reinterpret_cast <joyent::http_parser_settings const*> (&hooks_));
|
|
||||||
result.second = joyent::http_parser_execute (s, h,
|
|
||||||
static_cast <const char*> (data), bytes);
|
|
||||||
result.first = error_code{static_cast<int>(s->http_errno),
|
|
||||||
message_category()};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto
|
|
||||||
basic_parser::write_eof() ->
|
|
||||||
error_code
|
|
||||||
{
|
|
||||||
auto s (reinterpret_cast <joyent::http_parser*> (&state_));
|
|
||||||
auto h (reinterpret_cast <joyent::http_parser_settings const*> (&hooks_));
|
|
||||||
joyent::http_parser_execute (s, h, nullptr, 0);
|
|
||||||
return error_code{static_cast<int>(s->http_errno),
|
|
||||||
message_category()};
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void
|
|
||||||
basic_parser::check_header()
|
|
||||||
{
|
|
||||||
if (! value_.empty())
|
|
||||||
{
|
|
||||||
rfc2616::trim_right_in_place (value_);
|
|
||||||
on_field (field_, value_);
|
|
||||||
field_.clear();
|
|
||||||
value_.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::do_message_start ()
|
|
||||||
{
|
|
||||||
complete_ = false;
|
|
||||||
url_.clear();
|
|
||||||
status_.clear();
|
|
||||||
field_.clear();
|
|
||||||
value_.clear();
|
|
||||||
on_start();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::do_url (char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
url_.append (static_cast <char const*> (in), bytes);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::do_status (char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
status_.append (static_cast <char const*> (in), bytes);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::do_header_field (char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
check_header();
|
|
||||||
field_.append (static_cast <char const*> (in), bytes);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::do_header_value (char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
value_.append (static_cast <char const*> (in), bytes);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called when all the headers are complete but before
|
|
||||||
the content body, if present.
|
|
||||||
Returning 1 from here tells the joyent parser
|
|
||||||
that the message has no body (e.g. a HEAD request).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
basic_parser::do_headers_complete()
|
|
||||||
{
|
|
||||||
check_header();
|
|
||||||
auto const p (reinterpret_cast <joyent::http_parser const*> (&state_));
|
|
||||||
bool const keep_alive (joyent::http_should_keep_alive (p) != 0);
|
|
||||||
if (p->type == joyent::http_parser_type::HTTP_REQUEST)
|
|
||||||
return on_request (joyent::convert_http_method (
|
|
||||||
joyent::http_method(p->method)), url_,
|
|
||||||
p->http_major, p->http_minor, keep_alive, p->upgrade) ? 0 : 1;
|
|
||||||
return on_response (p->status_code, status_,
|
|
||||||
p->http_major, p->http_minor, keep_alive, p->upgrade) ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called repeatedly for the content body. The passed buffer
|
|
||||||
has already had the transfer-encoding removed.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
basic_parser::do_body (char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
on_body (in, bytes);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called when the both the headers and content body (if any) are complete. */
|
|
||||||
int
|
|
||||||
basic_parser::do_message_complete ()
|
|
||||||
{
|
|
||||||
complete_ = true;
|
|
||||||
on_complete();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::do_chunk_header()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::do_chunk_complete()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_message_start (joyent::http_parser* p)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_message_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_url (joyent::http_parser* p,
|
|
||||||
char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_url (in, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_status (joyent::http_parser* p,
|
|
||||||
char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_status (in, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_header_field (joyent::http_parser* p,
|
|
||||||
char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_header_field (in, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_header_value (joyent::http_parser* p,
|
|
||||||
char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_header_value (in, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_headers_complete (joyent::http_parser* p)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_headers_complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_body (joyent::http_parser* p,
|
|
||||||
char const* in, std::size_t bytes)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_body (
|
|
||||||
in, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_message_complete (joyent::http_parser* p)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_message_complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_chunk_header (joyent::http_parser* p)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_chunk_header();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
basic_parser::cb_chunk_complete (joyent::http_parser* p)
|
|
||||||
{
|
|
||||||
return reinterpret_cast <basic_parser*> (
|
|
||||||
p->data)->do_chunk_complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // http
|
|
||||||
} // beast
|
|
||||||
260
src/beast/beast/http/impl/basic_parser.ipp
Normal file
260
src/beast/beast/http/impl/basic_parser.ipp
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <beast/http/src/nodejs_parser.h>
|
||||||
|
#include <beast/http/rfc2616.h>
|
||||||
|
#include <beast/http/detail/error.h>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
basic_parser<Derived>::
|
||||||
|
basic_parser(basic_parser&& other)
|
||||||
|
{
|
||||||
|
state_ = other.state_;
|
||||||
|
state_.data = this;
|
||||||
|
complete_ = other.complete_;
|
||||||
|
url_ = std::move(other.url_);
|
||||||
|
status_ = std::move(other.status_);
|
||||||
|
field_ = std::move(other.field_);
|
||||||
|
value_ = std::move(other.value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
auto
|
||||||
|
basic_parser<Derived>::operator=(basic_parser&& other) ->
|
||||||
|
basic_parser&
|
||||||
|
{
|
||||||
|
state_ = other.state_;
|
||||||
|
state_.data = this;
|
||||||
|
complete_ = other.complete_;
|
||||||
|
url_ = std::move(other.url_);
|
||||||
|
status_ = std::move(other.status_);
|
||||||
|
field_ = std::move(other.field_);
|
||||||
|
value_ = std::move(other.value_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
basic_parser<Derived>::
|
||||||
|
basic_parser(basic_parser const& other)
|
||||||
|
{
|
||||||
|
state_ = other.state_;
|
||||||
|
state_.data = this;
|
||||||
|
complete_ = other.complete_;
|
||||||
|
url_ = other.url_;
|
||||||
|
status_ = other.status_;
|
||||||
|
field_ = other.field_;
|
||||||
|
value_ = other.value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
auto
|
||||||
|
basic_parser<Derived>::
|
||||||
|
operator=(basic_parser const& other) ->
|
||||||
|
basic_parser&
|
||||||
|
{
|
||||||
|
state_ = other.state_;
|
||||||
|
state_.data = this;
|
||||||
|
complete_ = other.complete_;
|
||||||
|
url_ = other.url_;
|
||||||
|
status_ = other.status_;
|
||||||
|
field_ = other.field_;
|
||||||
|
value_ = other.value_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
basic_parser<Derived>::basic_parser(bool request) noexcept
|
||||||
|
{
|
||||||
|
state_.data = this;
|
||||||
|
http_parser_init(&state_, request
|
||||||
|
? http_parser_type::HTTP_REQUEST
|
||||||
|
: http_parser_type::HTTP_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
std::size_t
|
||||||
|
basic_parser<Derived>::write(void const* data,
|
||||||
|
std::size_t size, error_code& ec)
|
||||||
|
{
|
||||||
|
ec_ = &ec;
|
||||||
|
auto const n = http_parser_execute(
|
||||||
|
&state_, hooks(),
|
||||||
|
static_cast<const char*>(data), size);
|
||||||
|
if(! ec)
|
||||||
|
ec = detail::make_error(
|
||||||
|
static_cast<int>(state_.http_errno));
|
||||||
|
if(ec)
|
||||||
|
return 0;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
void
|
||||||
|
basic_parser<Derived>::write_eof(error_code& ec)
|
||||||
|
{
|
||||||
|
ec_ = &ec;
|
||||||
|
http_parser_execute(
|
||||||
|
&state_, hooks(), nullptr, 0);
|
||||||
|
if(! ec)
|
||||||
|
ec = detail::make_error(
|
||||||
|
static_cast<int>(state_.http_errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
void
|
||||||
|
basic_parser<Derived>::check_header()
|
||||||
|
{
|
||||||
|
if (! value_.empty())
|
||||||
|
{
|
||||||
|
rfc2616::trim_right_in_place(value_);
|
||||||
|
call_on_field(field_, value_,
|
||||||
|
has_on_field<Derived>{});
|
||||||
|
field_.clear();
|
||||||
|
value_.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_message_start(http_parser* p)
|
||||||
|
{
|
||||||
|
auto& t = *reinterpret_cast<basic_parser*>(p->data);
|
||||||
|
t.complete_ = false;
|
||||||
|
t.url_.clear();
|
||||||
|
t.status_.clear();
|
||||||
|
t.field_.clear();
|
||||||
|
t.value_.clear();
|
||||||
|
t.call_on_start(has_on_start<Derived>{});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_url(http_parser* p,
|
||||||
|
char const* in, std::size_t bytes)
|
||||||
|
{
|
||||||
|
auto& t = *reinterpret_cast<basic_parser*>(p->data);
|
||||||
|
t.url_.append(in, bytes);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_status(http_parser* p,
|
||||||
|
char const* in, std::size_t bytes)
|
||||||
|
{
|
||||||
|
auto& t = *reinterpret_cast<basic_parser*>(p->data);
|
||||||
|
t.status_.append(in, bytes);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_header_field(http_parser* p,
|
||||||
|
char const* in, std::size_t bytes)
|
||||||
|
{
|
||||||
|
auto& t = *reinterpret_cast<basic_parser*>(p->data);
|
||||||
|
t.check_header();
|
||||||
|
t.field_.append(in, bytes);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_header_value(http_parser* p,
|
||||||
|
char const* in, std::size_t bytes)
|
||||||
|
{
|
||||||
|
auto& t = *reinterpret_cast<basic_parser*>(p->data);
|
||||||
|
t.value_.append(in, bytes);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when all the headers are complete but before
|
||||||
|
the content body, if present.
|
||||||
|
Returning 1 from here tells the nodejs parser
|
||||||
|
that the message has no body (e.g. a HEAD request).
|
||||||
|
*/
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_headers_complete(http_parser* p)
|
||||||
|
{
|
||||||
|
auto& t = *reinterpret_cast<basic_parser*>(p->data);
|
||||||
|
t.check_header();
|
||||||
|
t.call_on_headers_complete(*t.ec_,
|
||||||
|
has_on_headers_complete<Derived>{});
|
||||||
|
if(*t.ec_)
|
||||||
|
return 1;
|
||||||
|
bool const keep_alive =
|
||||||
|
http_should_keep_alive(p) != 0;
|
||||||
|
if(p->type == http_parser_type::HTTP_REQUEST)
|
||||||
|
{
|
||||||
|
t.call_on_request(convert_http_method(
|
||||||
|
http_method(p->method)), t.url_,
|
||||||
|
p->http_major, p->http_minor, keep_alive,
|
||||||
|
p->upgrade, has_on_request<Derived>{});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return t.call_on_response(p->status_code, t.status_,
|
||||||
|
p->http_major, p->http_minor, keep_alive,
|
||||||
|
p->upgrade, has_on_response<Derived>{}) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called repeatedly for the content body,
|
||||||
|
// after any transfer-encoding is applied.
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_body(http_parser* p,
|
||||||
|
char const* in, std::size_t bytes)
|
||||||
|
{
|
||||||
|
auto& t = *reinterpret_cast<basic_parser*>(p->data);
|
||||||
|
t.call_on_body(in, bytes, *t.ec_, has_on_body<Derived>{});
|
||||||
|
return *t.ec_ ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the both the headers
|
||||||
|
// and content body (if any) are complete.
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_message_complete(http_parser* p)
|
||||||
|
{
|
||||||
|
auto& t = *reinterpret_cast<basic_parser*>(p->data);
|
||||||
|
t.complete_ = true;
|
||||||
|
t.call_on_complete(has_on_complete<Derived>{});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_chunk_header(http_parser*)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Derived>
|
||||||
|
int
|
||||||
|
basic_parser<Derived>::cb_chunk_complete(http_parser*)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <beast/http/basic_url.h>
|
|
||||||
|
|
||||||
#include <beast/http/impl/joyent_parser.h>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
void
|
|
||||||
basic_url_base::parse_impl (string_ref s, boost::system::error_code& ec)
|
|
||||||
{
|
|
||||||
joyent::http_parser_url p;
|
|
||||||
|
|
||||||
value_type const* const data (s.data());
|
|
||||||
|
|
||||||
int const error (joyent::http_parser_parse_url (
|
|
||||||
data, s.size(), false, &p));
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
ec = boost::system::error_code (
|
|
||||||
boost::system::errc::invalid_argument,
|
|
||||||
boost::system::generic_category());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p.field_set & (1<<joyent::UF_SCHEMA)) != 0)
|
|
||||||
{
|
|
||||||
m_scheme = string_ref (
|
|
||||||
data + p.field_data [joyent::UF_SCHEMA].off,
|
|
||||||
p.field_data [joyent::UF_SCHEMA].len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_scheme = string_ref {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p.field_set & (1<<joyent::UF_HOST)) != 0)
|
|
||||||
{
|
|
||||||
m_host = string_ref (
|
|
||||||
data + p.field_data [joyent::UF_HOST].off,
|
|
||||||
p.field_data [joyent::UF_HOST].len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_host = string_ref {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p.field_set & (1<<joyent::UF_PORT)) != 0)
|
|
||||||
{
|
|
||||||
m_port = p.port;
|
|
||||||
m_port_string = string_ref (
|
|
||||||
data + p.field_data [joyent::UF_PORT].off,
|
|
||||||
p.field_data [joyent::UF_PORT].len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_port = 0;
|
|
||||||
m_port_string = string_ref {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p.field_set & (1<<joyent::UF_PATH)) != 0)
|
|
||||||
{
|
|
||||||
m_path = string_ref (
|
|
||||||
data + p.field_data [joyent::UF_PATH].off,
|
|
||||||
p.field_data [joyent::UF_PATH].len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_path = string_ref {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p.field_set & (1<<joyent::UF_QUERY)) != 0)
|
|
||||||
{
|
|
||||||
m_query = string_ref (
|
|
||||||
data + p.field_data [joyent::UF_QUERY].off,
|
|
||||||
p.field_data [joyent::UF_QUERY].len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_query = string_ref {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p.field_set & (1<<joyent::UF_FRAGMENT)) != 0)
|
|
||||||
{
|
|
||||||
m_fragment = string_ref (
|
|
||||||
data + p.field_data [joyent::UF_FRAGMENT].off,
|
|
||||||
p.field_data [joyent::UF_FRAGMENT].len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_fragment = string_ref {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p.field_set & (1<<joyent::UF_USERINFO)) != 0)
|
|
||||||
{
|
|
||||||
m_userinfo = string_ref (
|
|
||||||
data + p.field_data [joyent::UF_USERINFO].off,
|
|
||||||
p.field_data [joyent::UF_USERINFO].len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_userinfo = string_ref {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // detail
|
|
||||||
} // http
|
|
||||||
} // beast
|
|
||||||
320
src/beast/beast/http/impl/message.ipp
Normal file
320
src/beast/beast/http/impl/message.ipp
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_MESSAGE_IPP_INCLUDED
|
||||||
|
#define BEAST_HTTP_MESSAGE_IPP_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/chunk_encode.h>
|
||||||
|
#include <beast/http/type_check.h>
|
||||||
|
#include <beast/http/detail/writes.h>
|
||||||
|
#include <beast/http/detail/write_preparation.h>
|
||||||
|
#include <beast/http/rfc2616.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
message<isRequest, Body, Headers>::
|
||||||
|
message()
|
||||||
|
{
|
||||||
|
static_assert(is_Body<Body>::value,
|
||||||
|
"Body requirements not met");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
message<isRequest, Body, Headers>::
|
||||||
|
message(request_params params)
|
||||||
|
{
|
||||||
|
static_assert(is_Body<Body>::value,
|
||||||
|
"Body requirements not met");
|
||||||
|
static_assert(isRequest, "message is not a request");
|
||||||
|
this->method = params.method;
|
||||||
|
this->url = std::move(params.url);
|
||||||
|
version = params.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
message<isRequest, Body, Headers>::
|
||||||
|
message(response_params params)
|
||||||
|
{
|
||||||
|
static_assert(is_Body<Body>::value,
|
||||||
|
"Body requirements not met");
|
||||||
|
static_assert(! isRequest, "message is not a response");
|
||||||
|
this->status = params.status;
|
||||||
|
this->reason = std::move(params.reason);
|
||||||
|
version = params.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
template<class Streambuf>
|
||||||
|
void
|
||||||
|
message<isRequest, Body, Headers>::
|
||||||
|
write_firstline(Streambuf& streambuf,
|
||||||
|
std::true_type) const
|
||||||
|
{
|
||||||
|
detail::write(streambuf, to_string(this->method));
|
||||||
|
detail::write(streambuf, " ");
|
||||||
|
detail::write(streambuf, this->url);
|
||||||
|
switch(version)
|
||||||
|
{
|
||||||
|
case 10:
|
||||||
|
detail::write(streambuf, " HTTP/1.0\r\n");
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
detail::write(streambuf, " HTTP/1.1\r\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
detail::write(streambuf, " HTTP/");
|
||||||
|
detail::write(streambuf, version / 10);
|
||||||
|
detail::write(streambuf, ".");
|
||||||
|
detail::write(streambuf, version % 10);
|
||||||
|
detail::write(streambuf, "\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
template<class Streambuf>
|
||||||
|
void
|
||||||
|
message<isRequest, Body, Headers>::
|
||||||
|
write_firstline(Streambuf& streambuf,
|
||||||
|
std::false_type) const
|
||||||
|
{
|
||||||
|
switch(version)
|
||||||
|
{
|
||||||
|
case 10:
|
||||||
|
detail::write(streambuf, "HTTP/1.0 ");
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
detail::write(streambuf, "HTTP/1.1 ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
detail::write(streambuf, " HTTP/");
|
||||||
|
detail::write(streambuf, version / 10);
|
||||||
|
detail::write(streambuf, ".");
|
||||||
|
detail::write(streambuf, version % 10);
|
||||||
|
detail::write(streambuf, " ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
detail::write(streambuf, this->status);
|
||||||
|
detail::write(streambuf, " ");
|
||||||
|
detail::write(streambuf, this->reason);
|
||||||
|
detail::write(streambuf, "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::string
|
||||||
|
buffers_to_string(ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string s;
|
||||||
|
s.reserve(buffer_size(buffers));
|
||||||
|
for(auto const& b : buffers)
|
||||||
|
s.append(buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
// Diagnostic output only
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& os,
|
||||||
|
message<isRequest, Body, Headers> const& msg)
|
||||||
|
{
|
||||||
|
static_assert(is_WritableBody<Body>::value,
|
||||||
|
"WritableBody requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
detail::write_preparation<isRequest, Body, Headers> wp(msg);
|
||||||
|
wp.init(ec);
|
||||||
|
if(ec)
|
||||||
|
return os;
|
||||||
|
std::mutex m;
|
||||||
|
std::condition_variable cv;
|
||||||
|
bool ready = false;
|
||||||
|
resume_context resume{
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m);
|
||||||
|
ready = true;
|
||||||
|
cv.notify_one();
|
||||||
|
}};
|
||||||
|
auto copy = resume;
|
||||||
|
os << detail::buffers_to_string(wp.sb.data());
|
||||||
|
wp.sb.consume(wp.sb.size());
|
||||||
|
auto writef =
|
||||||
|
[&os, &wp](auto const& buffers)
|
||||||
|
{
|
||||||
|
if(wp.chunked)
|
||||||
|
os << detail::buffers_to_string(
|
||||||
|
chunk_encode(buffers));
|
||||||
|
else
|
||||||
|
os << detail::buffers_to_string(
|
||||||
|
buffers);
|
||||||
|
};
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto result = wp.w(std::move(copy), ec, writef);
|
||||||
|
if(ec)
|
||||||
|
return os;
|
||||||
|
if(result)
|
||||||
|
break;
|
||||||
|
if(boost::indeterminate(result))
|
||||||
|
{
|
||||||
|
copy = resume;
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
cv.wait(lock, [&]{ return ready; });
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wp.sb.consume(wp.sb.size());
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
auto result = wp.w(std::move(copy), ec, writef);
|
||||||
|
if(ec)
|
||||||
|
return os;
|
||||||
|
if(result)
|
||||||
|
break;
|
||||||
|
if(boost::indeterminate(result))
|
||||||
|
{
|
||||||
|
copy = resume;
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
cv.wait(lock, [&]{ return ready; });
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(wp.chunked)
|
||||||
|
{
|
||||||
|
// VFALCO Unfortunately the current interface to the
|
||||||
|
// Writer concept prevents us from using coalescing the
|
||||||
|
// final body chunk with the final chunk delimiter.
|
||||||
|
//
|
||||||
|
// write final chunk
|
||||||
|
os << detail::buffers_to_string(chunk_encode_final());
|
||||||
|
if(ec)
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
os << std::endl;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
set_connection(bool keep_alive,
|
||||||
|
message<isRequest, Body, Headers>& req)
|
||||||
|
{
|
||||||
|
if(req.version >= 11)
|
||||||
|
{
|
||||||
|
if(! keep_alive)
|
||||||
|
req.headers.replace("Connection", "close");
|
||||||
|
else
|
||||||
|
req.headers.erase("Connection");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(keep_alive)
|
||||||
|
req.headers.replace("Connection", "keep-alive");
|
||||||
|
else
|
||||||
|
req.headers.erase("Connection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Body, class Headers,
|
||||||
|
class OtherBody, class OtherAllocator>
|
||||||
|
void
|
||||||
|
set_connection(bool keep_alive,
|
||||||
|
message<false, Body, Headers>& resp,
|
||||||
|
message<true, OtherBody, OtherAllocator> const& req)
|
||||||
|
{
|
||||||
|
if(req.version >= 11)
|
||||||
|
{
|
||||||
|
if(rfc2616::token_in_list(req["Connection"], "close"))
|
||||||
|
keep_alive = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(! rfc2616::token_in_list(req["Connection"], "keep-alive"))
|
||||||
|
keep_alive = false;
|
||||||
|
}
|
||||||
|
set_connection(keep_alive, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Streambuf, class FieldSequence>
|
||||||
|
void
|
||||||
|
write_fields(Streambuf& streambuf, FieldSequence const& fields)
|
||||||
|
{
|
||||||
|
static_assert(is_Streambuf<Streambuf>::value,
|
||||||
|
"Streambuf requirements not met");
|
||||||
|
//static_assert(is_FieldSequence<FieldSequence>::value,
|
||||||
|
// "FieldSequence requirements not met");
|
||||||
|
for(auto const& field : fields)
|
||||||
|
{
|
||||||
|
detail::write(streambuf, field.name());
|
||||||
|
detail::write(streambuf, ": ");
|
||||||
|
detail::write(streambuf, field.value());
|
||||||
|
detail::write(streambuf, "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
bool
|
||||||
|
is_keep_alive(message<isRequest, Body, Headers> const& msg)
|
||||||
|
{
|
||||||
|
if(msg.version >= 11)
|
||||||
|
{
|
||||||
|
if(rfc2616::token_in_list(
|
||||||
|
msg.headers["Connection"], "close"))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(rfc2616::token_in_list(
|
||||||
|
msg.headers["Connection"], "keep-alive"))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
bool
|
||||||
|
is_upgrade(message<isRequest, Body, Headers> const& msg)
|
||||||
|
{
|
||||||
|
if(msg.version < 11)
|
||||||
|
return false;
|
||||||
|
if(rfc2616::token_in_list(
|
||||||
|
msg.headers["Connection"], "upgrade"))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/http/impl/message.ipp>
|
||||||
|
|
||||||
|
#endif
|
||||||
297
src/beast/beast/http/impl/read.ipp
Normal file
297
src/beast/beast/http/impl/read.ipp
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_READ_IPP_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_READ_IPP_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/type_check.h>
|
||||||
|
#include <beast/asio/async_completion.h>
|
||||||
|
#include <beast/asio/bind_handler.h>
|
||||||
|
#include <beast/asio/handler_alloc.h>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf,
|
||||||
|
bool isRequest, class Body, class Headers,
|
||||||
|
class Handler>
|
||||||
|
class read_op
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
handler_alloc<char, Handler>;
|
||||||
|
|
||||||
|
using parser_type =
|
||||||
|
parser<isRequest, Body, Headers>;
|
||||||
|
|
||||||
|
using message_type =
|
||||||
|
message<isRequest, Body, Headers>;
|
||||||
|
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
Stream& s;
|
||||||
|
Streambuf& sb;
|
||||||
|
message_type& m;
|
||||||
|
parser_type p;
|
||||||
|
Handler h;
|
||||||
|
bool cont;
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
data(DeducedHandler&& h_, Stream& s_,
|
||||||
|
Streambuf& sb_, message_type& m_)
|
||||||
|
: s(s_)
|
||||||
|
, sb(sb_)
|
||||||
|
, m(m_)
|
||||||
|
, h(std::forward<DeducedHandler>(h_))
|
||||||
|
, cont(boost_asio_handler_cont_helpers::
|
||||||
|
is_continuation(h))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<data> d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
read_op(read_op&&) = default;
|
||||||
|
read_op(read_op const&) = default;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
read_op(DeducedHandler&& h, Stream&s, Args&&... args)
|
||||||
|
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||||
|
std::forward<DeducedHandler>(h), s,
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
(*this)(error_code{}, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code ec,
|
||||||
|
std::size_t bytes_transferred, bool again = true);
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_allocate(
|
||||||
|
std::size_t size, read_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
allocate(size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, read_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
deallocate(p, size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_is_continuation(read_op* op)
|
||||||
|
{
|
||||||
|
return op->d_->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
friend
|
||||||
|
auto asio_handler_invoke(Function&& f, read_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::
|
||||||
|
invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf,
|
||||||
|
bool isRequest, class Body, class Headers,
|
||||||
|
class Handler>
|
||||||
|
void
|
||||||
|
read_op<Stream, Streambuf, isRequest, Body, Headers, Handler>::
|
||||||
|
operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.cont = d.cont || again;
|
||||||
|
while(d.state != 99)
|
||||||
|
{
|
||||||
|
switch(d.state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
auto const used =
|
||||||
|
d.p.write(d.sb.data(), ec);
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
d.s.get_io_service().post(
|
||||||
|
bind_handler(std::move(*this), ec, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d.sb.consume(used);
|
||||||
|
if(d.p.complete())
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
d.m = d.p.release();
|
||||||
|
d.s.get_io_service().post(
|
||||||
|
bind_handler(std::move(*this), ec, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d.state = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// read
|
||||||
|
d.state = 2;
|
||||||
|
d.s.async_read_some(d.sb.prepare(
|
||||||
|
read_size_helper(d.sb, 65536)),
|
||||||
|
std::move(*this));
|
||||||
|
return;
|
||||||
|
|
||||||
|
// got data
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
if(ec == boost::asio::error::eof)
|
||||||
|
{
|
||||||
|
if(! d.p.started())
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Caller will see eof on next read.
|
||||||
|
ec = {};
|
||||||
|
d.p.write_eof(ec);
|
||||||
|
if(! ec)
|
||||||
|
{
|
||||||
|
assert(d.p.complete());
|
||||||
|
d.m = d.p.release();
|
||||||
|
}
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d.sb.commit(bytes_transferred);
|
||||||
|
d.sb.consume(d.p.write(d.sb.data(), ec));
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(d.p.complete())
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
d.m = d.p.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d.state = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.h(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class SyncReadStream, class Streambuf,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||||
|
message<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_ReadableBody<Body>::value,
|
||||||
|
"ReadableBody requirements not met");
|
||||||
|
parser<isRequest, Body, Headers> p;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
auto used =
|
||||||
|
p.write(streambuf.data(), ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
streambuf.consume(used);
|
||||||
|
if(p.complete())
|
||||||
|
{
|
||||||
|
m = p.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
streambuf.commit(stream.read_some(
|
||||||
|
streambuf.prepare(read_size_helper(
|
||||||
|
streambuf, 65536)), ec));
|
||||||
|
if(ec && ec != boost::asio::error::eof)
|
||||||
|
return;
|
||||||
|
if(ec == boost::asio::error::eof)
|
||||||
|
{
|
||||||
|
if(! p.started())
|
||||||
|
return;
|
||||||
|
// Caller will see eof on next read.
|
||||||
|
ec = {};
|
||||||
|
p.write_eof(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
assert(p.complete());
|
||||||
|
m = p.release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class AsyncReadStream, class Streambuf,
|
||||||
|
bool isRequest, class Body, class Headers,
|
||||||
|
class CompletionToken>
|
||||||
|
auto
|
||||||
|
async_read(AsyncReadStream& stream, Streambuf& streambuf,
|
||||||
|
message<isRequest, Body, Headers>& m,
|
||||||
|
CompletionToken&& token)
|
||||||
|
{
|
||||||
|
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
|
||||||
|
"AsyncReadStream requirements not met");
|
||||||
|
static_assert(is_Streambuf<Streambuf>::value,
|
||||||
|
"Streambuf requirements not met");
|
||||||
|
static_assert(is_ReadableBody<Body>::value,
|
||||||
|
"ReadableBody requirements not met");
|
||||||
|
beast::async_completion<CompletionToken,
|
||||||
|
void(error_code)> completion(token);
|
||||||
|
detail::read_op<AsyncReadStream, Streambuf,
|
||||||
|
isRequest, Body, Headers, decltype(
|
||||||
|
completion.handler)>{completion.handler,
|
||||||
|
stream, streambuf, m};
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
396
src/beast/beast/http/impl/write.ipp
Normal file
396
src/beast/beast/http/impl/write.ipp
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_WRITE_IPP_INCLUDED
|
||||||
|
#define BEAST_HTTP_WRITE_IPP_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/chunk_encode.h>
|
||||||
|
#include <beast/http/resume_context.h>
|
||||||
|
#include <beast/http/type_check.h>
|
||||||
|
#include <beast/http/detail/writes.h>
|
||||||
|
#include <beast/http/detail/write_preparation.h>
|
||||||
|
#include <beast/asio/append_buffers.h>
|
||||||
|
#include <beast/asio/async_completion.h>
|
||||||
|
#include <beast/asio/bind_handler.h>
|
||||||
|
#include <beast/asio/handler_alloc.h>
|
||||||
|
#include <beast/asio/streambuf.h>
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
#include <boost/asio/write.hpp>
|
||||||
|
#include <boost/logic/tribool.hpp>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <beast/cxx17/type_traits.h> // <type_traits>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class Stream, class Handler,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
class write_op
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
handler_alloc<char, Handler>;
|
||||||
|
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
Stream& s;
|
||||||
|
// VFALCO How do we use handler_alloc in write_preparation?
|
||||||
|
write_preparation<
|
||||||
|
isRequest, Body, Headers> wp;
|
||||||
|
Handler h;
|
||||||
|
resume_context resume;
|
||||||
|
resume_context copy;
|
||||||
|
bool cont;
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
data(DeducedHandler&& h_, Stream& s_,
|
||||||
|
message<isRequest, Body, Headers> const& m_)
|
||||||
|
: s(s_)
|
||||||
|
, wp(m_)
|
||||||
|
, h(std::forward<DeducedHandler>(h_))
|
||||||
|
, cont(boost_asio_handler_cont_helpers::
|
||||||
|
is_continuation(h))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<data> d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
write_op(write_op&&) = default;
|
||||||
|
write_op(write_op const&) = default;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
write_op(DeducedHandler&& h, Stream& s, Args&&... args)
|
||||||
|
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||||
|
std::forward<DeducedHandler>(h), s,
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.resume = {
|
||||||
|
[self = *this]() mutable
|
||||||
|
{
|
||||||
|
self.d_->cont = false;
|
||||||
|
auto& ios = self.d_->s.get_io_service();
|
||||||
|
ios.dispatch(bind_handler(std::move(self),
|
||||||
|
error_code{}, 0, false));
|
||||||
|
}};
|
||||||
|
d.copy = d.resume;
|
||||||
|
(*this)(error_code{}, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit
|
||||||
|
write_op(std::shared_ptr<data> d)
|
||||||
|
: d_(std::move(d))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code ec,
|
||||||
|
std::size_t bytes_transferred, bool again = true);
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_allocate(
|
||||||
|
std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
allocate(size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
deallocate(p, size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_is_continuation(write_op* op)
|
||||||
|
{
|
||||||
|
return op->d_->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
friend
|
||||||
|
auto asio_handler_invoke(Function&& f, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::
|
||||||
|
invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Stream, class Handler,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
write_op<Stream, Handler, isRequest, Body, Headers>::
|
||||||
|
operator()(error_code ec, std::size_t, bool again)
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.cont = d.cont || again;
|
||||||
|
while(! ec && d.state != 99)
|
||||||
|
{
|
||||||
|
switch(d.state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
d.wp.init(ec);
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
d.s.get_io_service().post(bind_handler(
|
||||||
|
std::move(*this), ec, 0, false));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d.state = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
auto const result = d.wp.w(std::move(d.copy), ec,
|
||||||
|
[&](auto const& buffers)
|
||||||
|
{
|
||||||
|
// write headers and body
|
||||||
|
if(d.wp.chunked)
|
||||||
|
boost::asio::async_write(d.s,
|
||||||
|
append_buffers(d.wp.sb.data(),
|
||||||
|
chunk_encode(buffers)),
|
||||||
|
std::move(*this));
|
||||||
|
else
|
||||||
|
boost::asio::async_write(d.s,
|
||||||
|
append_buffers(d.wp.sb.data(),
|
||||||
|
buffers), std::move(*this));
|
||||||
|
});
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
d.s.get_io_service().post(bind_handler(
|
||||||
|
std::move(*this), ec, false));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(boost::indeterminate(result))
|
||||||
|
{
|
||||||
|
// suspend
|
||||||
|
d.copy = d.resume;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(result)
|
||||||
|
d.state = d.wp.chunked ? 4 : 5;
|
||||||
|
else
|
||||||
|
d.state = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sent headers and body
|
||||||
|
case 2:
|
||||||
|
d.wp.sb.consume(d.wp.sb.size());
|
||||||
|
d.state = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
auto const result = d.wp.w(std::move(d.copy), ec,
|
||||||
|
[&](auto const& buffers)
|
||||||
|
{
|
||||||
|
// write body
|
||||||
|
if(d.wp.chunked)
|
||||||
|
boost::asio::async_write(d.s,
|
||||||
|
chunk_encode(buffers),
|
||||||
|
std::move(*this));
|
||||||
|
else
|
||||||
|
boost::asio::async_write(d.s,
|
||||||
|
buffers, std::move(*this));
|
||||||
|
});
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(boost::indeterminate(result))
|
||||||
|
{
|
||||||
|
// suspend
|
||||||
|
d.copy = d.resume;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(result)
|
||||||
|
d.state = d.wp.chunked ? 4 : 5;
|
||||||
|
else
|
||||||
|
d.state = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
// VFALCO Unfortunately the current interface to the
|
||||||
|
// Writer concept prevents us from using coalescing the
|
||||||
|
// final body chunk with the final chunk delimiter.
|
||||||
|
//
|
||||||
|
// write final chunk
|
||||||
|
d.state = 5;
|
||||||
|
boost::asio::async_write(d.s,
|
||||||
|
chunk_encode_final(), std::move(*this));
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
if(d.wp.close)
|
||||||
|
{
|
||||||
|
// VFALCO TODO Decide on an error code
|
||||||
|
ec = boost::asio::error::eof;
|
||||||
|
}
|
||||||
|
d.state = 99;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.h(ec);
|
||||||
|
d.resume = {};
|
||||||
|
d.copy = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class SyncWriteStream,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
write(SyncWriteStream& stream,
|
||||||
|
message<isRequest, Body, Headers> const& msg,
|
||||||
|
boost::system::error_code& ec)
|
||||||
|
{
|
||||||
|
static_assert(is_WritableBody<Body>::value,
|
||||||
|
"WritableBody requirements not met");
|
||||||
|
detail::write_preparation<isRequest, Body, Headers> wp(msg);
|
||||||
|
wp.init(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
std::mutex m;
|
||||||
|
std::condition_variable cv;
|
||||||
|
bool ready = false;
|
||||||
|
resume_context resume{
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m);
|
||||||
|
ready = true;
|
||||||
|
cv.notify_one();
|
||||||
|
}};
|
||||||
|
auto copy = resume;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto result = wp.w(std::move(copy), ec,
|
||||||
|
[&](auto const& buffers)
|
||||||
|
{
|
||||||
|
// write headers and body
|
||||||
|
if(wp.chunked)
|
||||||
|
boost::asio::write(stream, append_buffers(
|
||||||
|
wp.sb.data(), chunk_encode(buffers)), ec);
|
||||||
|
else
|
||||||
|
boost::asio::write(stream, append_buffers(
|
||||||
|
wp.sb.data(), buffers), ec);
|
||||||
|
});
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(result)
|
||||||
|
break;
|
||||||
|
if(boost::indeterminate(result))
|
||||||
|
{
|
||||||
|
boost::asio::write(stream, wp.sb.data(), ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
wp.sb.consume(wp.sb.size());
|
||||||
|
copy = resume;
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
cv.wait(lock, [&]{ return ready; });
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wp.sb.consume(wp.sb.size());
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
auto result = wp.w(std::move(copy), ec,
|
||||||
|
[&](auto const& buffers)
|
||||||
|
{
|
||||||
|
// write body
|
||||||
|
if(wp.chunked)
|
||||||
|
boost::asio::write(stream,
|
||||||
|
chunk_encode(buffers), ec);
|
||||||
|
else
|
||||||
|
boost::asio::write(stream, buffers, ec);
|
||||||
|
});
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(result)
|
||||||
|
break;
|
||||||
|
if(boost::indeterminate(result))
|
||||||
|
{
|
||||||
|
copy = resume;
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
cv.wait(lock, [&]{ return ready; });
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(wp.chunked)
|
||||||
|
{
|
||||||
|
// VFALCO Unfortunately the current interface to the
|
||||||
|
// Writer concept prevents us from using coalescing the
|
||||||
|
// final body chunk with the final chunk delimiter.
|
||||||
|
//
|
||||||
|
// write final chunk
|
||||||
|
boost::asio::write(stream, chunk_encode_final(), ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(wp.close)
|
||||||
|
{
|
||||||
|
// VFALCO TODO Decide on an error code
|
||||||
|
ec = boost::asio::error::eof;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class AsyncWriteStream,
|
||||||
|
bool isRequest, class Body, class Headers,
|
||||||
|
class CompletionToken>
|
||||||
|
auto
|
||||||
|
async_write(AsyncWriteStream& stream,
|
||||||
|
message<isRequest, Body, Headers> const& msg,
|
||||||
|
CompletionToken&& token)
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
is_AsyncWriteStream<AsyncWriteStream>::value,
|
||||||
|
"AsyncWriteStream requirements not met");
|
||||||
|
static_assert(is_WritableBody<Body>::value,
|
||||||
|
"WritableBody requirements not met");
|
||||||
|
beast::async_completion<CompletionToken,
|
||||||
|
void(error_code)> completion(token);
|
||||||
|
detail::write_op<AsyncWriteStream, decltype(completion.handler),
|
||||||
|
isRequest, Body, Headers>{completion.handler, stream, msg};
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,12 +20,171 @@
|
|||||||
#ifndef BEAST_HTTP_MESSAGE_H_INCLUDED
|
#ifndef BEAST_HTTP_MESSAGE_H_INCLUDED
|
||||||
#define BEAST_HTTP_MESSAGE_H_INCLUDED
|
#define BEAST_HTTP_MESSAGE_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/http/basic_parser.h>
|
#include <beast/http/headers.h>
|
||||||
|
#include <beast/http/method.h>
|
||||||
|
#include <beast/asio/buffers_debug.h>
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
struct request_fields
|
||||||
|
{
|
||||||
|
http::method_t method;
|
||||||
|
std::string url;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response_fields
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
std::string reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
struct request_params
|
||||||
|
{
|
||||||
|
http::method_t method;
|
||||||
|
std::string url;
|
||||||
|
int version;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response_params
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
std::string reason;
|
||||||
|
int version;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A HTTP message.
|
||||||
|
|
||||||
|
A message can be a request or response, depending on the `isRequest`
|
||||||
|
template argument value. Requests and responses have different types,
|
||||||
|
so functions may be overloaded on them if desired.
|
||||||
|
|
||||||
|
The `Body` template argument type determines the model used
|
||||||
|
to read or write the content body of the message.
|
||||||
|
|
||||||
|
@tparam isRequest `true` if this is a request.
|
||||||
|
|
||||||
|
@tparam Body A type meeting the requirements of Body.
|
||||||
|
|
||||||
|
@tparam Headers A type meeting the requirements of Headers.
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
struct message
|
||||||
|
: std::conditional_t<isRequest,
|
||||||
|
detail::request_fields, detail::response_fields>
|
||||||
|
{
|
||||||
|
/** The trait type characterizing the body.
|
||||||
|
|
||||||
|
The body member will be of type body_type::value_type.
|
||||||
|
*/
|
||||||
|
using body_type = Body;
|
||||||
|
using headers_type = Headers;
|
||||||
|
|
||||||
|
using is_request =
|
||||||
|
std::integral_constant<bool, isRequest>;
|
||||||
|
|
||||||
|
int version; // 10 or 11
|
||||||
|
headers_type headers;
|
||||||
|
typename Body::value_type body;
|
||||||
|
|
||||||
|
message();
|
||||||
|
message(message&&) = default;
|
||||||
|
message(message const&) = default;
|
||||||
|
message& operator=(message&&) = default;
|
||||||
|
message& operator=(message const&) = default;
|
||||||
|
|
||||||
|
/** Construct a HTTP request.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
message(request_params params);
|
||||||
|
|
||||||
|
/** Construct a HTTP response.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
message(response_params params);
|
||||||
|
|
||||||
|
/// Serialize the request or response line to a Streambuf.
|
||||||
|
template<class Streambuf>
|
||||||
|
void
|
||||||
|
write_firstline(Streambuf& streambuf) const
|
||||||
|
{
|
||||||
|
write_firstline(streambuf,
|
||||||
|
std::integral_constant<bool, isRequest>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Diagnostics only
|
||||||
|
template<bool, class, class>
|
||||||
|
friend
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& os,
|
||||||
|
message const& m);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<class Streambuf>
|
||||||
|
void
|
||||||
|
write_firstline(Streambuf& streambuf,
|
||||||
|
std::true_type) const;
|
||||||
|
|
||||||
|
template<class Streambuf>
|
||||||
|
void
|
||||||
|
write_firstline(Streambuf& streambuf,
|
||||||
|
std::false_type) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if ! GENERATING_DOCS
|
||||||
|
|
||||||
|
/// A typical HTTP request
|
||||||
|
template<class Body,
|
||||||
|
class Headers = basic_headers<std::allocator<char>>>
|
||||||
|
using request = message<true, Body, Headers>;
|
||||||
|
|
||||||
|
/// A typical HTTP response
|
||||||
|
template<class Body,
|
||||||
|
class Headers = basic_headers<std::allocator<char>>>
|
||||||
|
using response = message<false, Body, Headers>;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For diagnostic output only
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& os,
|
||||||
|
message<isRequest, Body, Headers> const& m);
|
||||||
|
|
||||||
|
/// Write a FieldSequence to a Streambuf.
|
||||||
|
template<class Streambuf, class FieldSequence>
|
||||||
|
void
|
||||||
|
write_fields(Streambuf& streambuf, FieldSequence const& fields);
|
||||||
|
|
||||||
|
/// Returns `true` if a message indicates a keep alive
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
bool
|
||||||
|
is_keep_alive(message<isRequest, Body, Headers> const& msg);
|
||||||
|
|
||||||
|
/// Returns `true` if a message indicates a HTTP Upgrade request or response
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
bool
|
||||||
|
is_upgrade(message<isRequest, Body, Headers> const& msg);
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/http/impl/message.ipp>
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#include <beast/http/method.h>
|
#include <beast/http/method.h>
|
||||||
#include <beast/http/headers.h>
|
#include <beast/http/headers.h>
|
||||||
#include <beast/ci_char_traits.h>
|
#include <beast/ci_char_traits.h>
|
||||||
#include <boost/intrusive/list.hpp>
|
#include <beast/http/detail/writes.h>
|
||||||
#include <boost/intrusive/set.hpp>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
@@ -34,7 +193,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace deprecated_http {
|
||||||
|
|
||||||
inline
|
inline
|
||||||
std::pair<int, int>
|
std::pair<int, int>
|
||||||
@@ -70,17 +229,16 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
~message() = default;
|
~message() = default;
|
||||||
message (message const&) = delete;
|
message (message const&) = default;
|
||||||
message& operator= (message const&) = delete;
|
message (message&& other) = default;
|
||||||
|
message& operator= (message const&) = default;
|
||||||
|
message& operator= (message&& other) = default;
|
||||||
|
|
||||||
template <class = void>
|
template <class = void>
|
||||||
message();
|
message();
|
||||||
|
|
||||||
message (message&& other) = default;
|
|
||||||
message& operator= (message&& other) = default;
|
|
||||||
|
|
||||||
// Memberspace
|
// Memberspace
|
||||||
beast::http::headers headers;
|
beast::http::headers<std::allocator<char>> headers;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
request() const
|
request() const
|
||||||
@@ -221,49 +379,31 @@ write (Streambuf& stream, message const& m)
|
|||||||
{
|
{
|
||||||
if (m.request())
|
if (m.request())
|
||||||
{
|
{
|
||||||
write (stream, to_string(m.method()));
|
http::detail::write (stream, to_string(m.method()));
|
||||||
write (stream, " ");
|
http::detail::write (stream, " ");
|
||||||
write (stream, m.url());
|
http::detail::write (stream, m.url());
|
||||||
write (stream, " HTTP/");
|
http::detail::write (stream, " HTTP/");
|
||||||
write (stream, std::to_string(m.version().first));
|
http::detail::write (stream, std::to_string(m.version().first));
|
||||||
write (stream, ".");
|
http::detail::write (stream, ".");
|
||||||
write (stream, std::to_string(m.version().second));
|
http::detail::write (stream, std::to_string(m.version().second));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write (stream, "HTTP/");
|
http::detail::write (stream, "HTTP/");
|
||||||
write (stream, std::to_string(m.version().first));
|
http::detail::write (stream, std::to_string(m.version().first));
|
||||||
write (stream, ".");
|
http::detail::write (stream, ".");
|
||||||
write (stream, std::to_string(m.version().second));
|
http::detail::write (stream, std::to_string(m.version().second));
|
||||||
write (stream, " ");
|
http::detail::write (stream, " ");
|
||||||
write (stream, std::to_string(m.status()));
|
http::detail::write (stream, std::to_string(m.status()));
|
||||||
write (stream, " ");
|
http::detail::write (stream, " ");
|
||||||
write (stream, m.reason());
|
http::detail::write (stream, m.reason());
|
||||||
}
|
}
|
||||||
write (stream, "\r\n");
|
http::detail::write (stream, "\r\n");
|
||||||
write(stream, m.headers);
|
write_fields(stream, m.headers);
|
||||||
write (stream, "\r\n");
|
http::detail::write (stream, "\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class = void>
|
} // deprecated_http
|
||||||
std::string
|
|
||||||
to_string (message const& m)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
if (m.request())
|
|
||||||
ss << to_string(m.method()) << " " << m.url() << " HTTP/" <<
|
|
||||||
std::to_string(m.version().first) << "." <<
|
|
||||||
std::to_string(m.version().second) << "\r\n";
|
|
||||||
else
|
|
||||||
ss << "HTTP/" << std::to_string(m.version().first) << "." <<
|
|
||||||
std::to_string(m.version().second) << " " <<
|
|
||||||
std::to_string(m.status()) << " " << m.reason() << "\r\n";
|
|
||||||
ss << to_string(m.headers);
|
|
||||||
ss << "\r\n";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // http
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -78,8 +78,51 @@ enum class method_t
|
|||||||
http_unlink
|
http_unlink
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class = void>
|
||||||
std::string
|
std::string
|
||||||
to_string (method_t m);
|
to_string(method_t m)
|
||||||
|
{
|
||||||
|
switch(m)
|
||||||
|
{
|
||||||
|
case method_t::http_delete: return "DELETE";
|
||||||
|
case method_t::http_get: return "GET";
|
||||||
|
case method_t::http_head: return "HEAD";
|
||||||
|
case method_t::http_post: return "POST";
|
||||||
|
case method_t::http_put: return "PUT";
|
||||||
|
|
||||||
|
case method_t::http_connect: return "CONNECT";
|
||||||
|
case method_t::http_options: return "OPTIONS";
|
||||||
|
case method_t::http_trace: return "TRACE";
|
||||||
|
|
||||||
|
case method_t::http_copy: return "COPY";
|
||||||
|
case method_t::http_lock: return "LOCK";
|
||||||
|
case method_t::http_mkcol: return "MKCOL";
|
||||||
|
case method_t::http_move: return "MOVE";
|
||||||
|
case method_t::http_propfind: return "PROPFIND";
|
||||||
|
case method_t::http_proppatch: return "PROPPATCH";
|
||||||
|
case method_t::http_search: return "SEARCH";
|
||||||
|
case method_t::http_unlock: return "UNLOCK";
|
||||||
|
|
||||||
|
case method_t::http_report: return "REPORT";
|
||||||
|
case method_t::http_mkactivity: return "MKACTIVITY";
|
||||||
|
case method_t::http_checkout: return "CHECKOUT";
|
||||||
|
case method_t::http_merge: return "MERGE";
|
||||||
|
|
||||||
|
case method_t::http_msearch: return "MSEARCH";
|
||||||
|
case method_t::http_notify: return "NOTIFY";
|
||||||
|
case method_t::http_subscribe: return "SUBSCRIBE";
|
||||||
|
case method_t::http_unsubscribe: return "UNSUBSCRIBE";
|
||||||
|
|
||||||
|
case method_t::http_patch: return "PATCH";
|
||||||
|
case method_t::http_purge: return "PURGE";
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
return "GET";
|
||||||
|
}
|
||||||
|
|
||||||
template <class Stream>
|
template <class Stream>
|
||||||
Stream&
|
Stream&
|
||||||
@@ -89,10 +132,60 @@ operator<< (Stream& s, method_t m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the string corresponding to the numeric HTTP status code. */
|
/** Returns the string corresponding to the numeric HTTP status code. */
|
||||||
|
template<class = void>
|
||||||
std::string
|
std::string
|
||||||
status_text (int status);
|
status_text (int status)
|
||||||
|
{
|
||||||
|
switch(status)
|
||||||
|
{
|
||||||
|
case 100: return "Continue";
|
||||||
|
case 101: return "Switching Protocols";
|
||||||
|
case 200: return "OK";
|
||||||
|
case 201: return "Created";
|
||||||
|
case 202: return "Accepted";
|
||||||
|
case 203: return "Non-Authoritative Information";
|
||||||
|
case 204: return "No Content";
|
||||||
|
case 205: return "Reset Content";
|
||||||
|
case 206: return "Partial Content";
|
||||||
|
case 300: return "Multiple Choices";
|
||||||
|
case 301: return "Moved Permanently";
|
||||||
|
case 302: return "Found";
|
||||||
|
case 303: return "See Other";
|
||||||
|
case 304: return "Not Modified";
|
||||||
|
case 305: return "Use Proxy";
|
||||||
|
//case 306: return "<reserved>";
|
||||||
|
case 307: return "Temporary Redirect";
|
||||||
|
case 400: return "Bad Request";
|
||||||
|
case 401: return "Unauthorized";
|
||||||
|
case 402: return "Payment Required";
|
||||||
|
case 403: return "Forbidden";
|
||||||
|
case 404: return "Not Found";
|
||||||
|
case 405: return "Method Not Allowed";
|
||||||
|
case 406: return "Not Acceptable";
|
||||||
|
case 407: return "Proxy Authentication Required";
|
||||||
|
case 408: return "Request Timeout";
|
||||||
|
case 409: return "Conflict";
|
||||||
|
case 410: return "Gone";
|
||||||
|
case 411: return "Length Required";
|
||||||
|
case 412: return "Precondition Failed";
|
||||||
|
case 413: return "Request Entity Too Large";
|
||||||
|
case 414: return "Request-URI Too Long";
|
||||||
|
case 415: return "Unsupported Media Type";
|
||||||
|
case 416: return "Requested Range Not Satisfiable";
|
||||||
|
case 417: return "Expectation Failed";
|
||||||
|
case 500: return "Internal Server Error";
|
||||||
|
case 501: return "Not Implemented";
|
||||||
|
case 502: return "Bad Gateway";
|
||||||
|
case 503: return "Service Unavailable";
|
||||||
|
case 504: return "Gateway Timeout";
|
||||||
|
case 505: return "HTTP Version Not Supported";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "Unknown HTTP status";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
} // http
|
||||||
}
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,6 +20,157 @@
|
|||||||
#ifndef BEAST_HTTP_PARSER_H_INCLUDED
|
#ifndef BEAST_HTTP_PARSER_H_INCLUDED
|
||||||
#define BEAST_HTTP_PARSER_H_INCLUDED
|
#define BEAST_HTTP_PARSER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/basic_parser.h>
|
||||||
|
#include <beast/http/error.h>
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <functional>
|
||||||
|
#include <beast/cxx17/type_traits.h> // <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/** A HTTP parser.
|
||||||
|
|
||||||
|
The parser may only be used once.
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
class parser
|
||||||
|
: public basic_parser<parser<isRequest, Body, Headers>>
|
||||||
|
{
|
||||||
|
using message_type =
|
||||||
|
message<isRequest, Body, Headers>;
|
||||||
|
|
||||||
|
message_type m_;
|
||||||
|
typename message_type::body_type::reader r_;
|
||||||
|
bool started_ = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
parser(parser&&) = default;
|
||||||
|
|
||||||
|
parser()
|
||||||
|
: http::basic_parser<parser>(isRequest)
|
||||||
|
, r_(m_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if at least one byte has been processed
|
||||||
|
bool
|
||||||
|
started()
|
||||||
|
{
|
||||||
|
return started_;
|
||||||
|
}
|
||||||
|
|
||||||
|
message_type
|
||||||
|
release()
|
||||||
|
{
|
||||||
|
return std::move(m_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class http::basic_parser<parser>;
|
||||||
|
|
||||||
|
void
|
||||||
|
on_start()
|
||||||
|
{
|
||||||
|
started_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_field(std::string const& field, std::string const& value)
|
||||||
|
{
|
||||||
|
m_.headers.insert(field, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_headers_complete(error_code&)
|
||||||
|
{
|
||||||
|
// vFALCO TODO Decode the Content-Length and
|
||||||
|
// Transfer-Encoding, see if we can reserve the buffer.
|
||||||
|
//
|
||||||
|
// r_.reserve(content_length)
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_request(http::method_t method, std::string const& url,
|
||||||
|
int major, int minor, bool keep_alive, bool upgrade,
|
||||||
|
std::true_type)
|
||||||
|
{
|
||||||
|
m_.method = method;
|
||||||
|
m_.url = url;
|
||||||
|
m_.version = major * 10 + minor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_request(http::method_t, std::string const&,
|
||||||
|
int, int, bool, bool,
|
||||||
|
std::false_type)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_request(http::method_t method, std::string const& url,
|
||||||
|
int major, int minor, bool keep_alive, bool upgrade)
|
||||||
|
{
|
||||||
|
return on_request(method, url,
|
||||||
|
major, minor, keep_alive, upgrade,
|
||||||
|
typename message_type::is_request{});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_response(int status, std::string const& reason,
|
||||||
|
int major, int minor, bool keep_alive, bool upgrade,
|
||||||
|
std::true_type)
|
||||||
|
{
|
||||||
|
m_.status = status;
|
||||||
|
m_.reason = reason;
|
||||||
|
m_.version = major * 10 + minor;
|
||||||
|
// VFALCO TODO return expect_body_
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_response(int, std::string const&, int, int, bool, bool,
|
||||||
|
std::false_type)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_response(int status, std::string const& reason,
|
||||||
|
int major, int minor, bool keep_alive, bool upgrade)
|
||||||
|
{
|
||||||
|
return on_response(
|
||||||
|
status, reason, major, minor, keep_alive, upgrade,
|
||||||
|
std::integral_constant<bool, ! message_type::is_request::value>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_body(void const* data,
|
||||||
|
std::size_t size, error_code& ec)
|
||||||
|
{
|
||||||
|
r_.write(data, size, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_complete()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//
|
||||||
|
// LEGACY
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <beast/http/basic_parser.h>
|
||||||
#include <beast/http/message.h>
|
#include <beast/http/message.h>
|
||||||
#include <beast/http/body.h>
|
#include <beast/http/body.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -27,167 +178,105 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace deprecated_http {
|
||||||
|
|
||||||
/** Parser for HTTP messages.
|
/** Parser for HTTP messages.
|
||||||
The result is stored in a message object.
|
The result is stored in a message object.
|
||||||
*/
|
*/
|
||||||
class parser : public beast::http::basic_parser
|
class parser
|
||||||
|
: public beast::http::basic_parser<parser>
|
||||||
{
|
{
|
||||||
private:
|
// friend class basic_parser<parser>;
|
||||||
std::reference_wrapper <message> message_;
|
|
||||||
|
message& m_;
|
||||||
std::function<void(void const*, std::size_t)> write_body_;
|
std::function<void(void const*, std::size_t)> write_body_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
parser(parser&&) = default;
|
||||||
|
parser(parser const&) = delete;
|
||||||
|
parser& operator=(parser&&) = delete;
|
||||||
|
parser& operator=(parser const&) = delete;
|
||||||
|
|
||||||
/** Construct a parser for HTTP request or response.
|
/** Construct a parser for HTTP request or response.
|
||||||
The headers plus request or status line are stored in message.
|
The headers plus request or status line are stored in message.
|
||||||
The content-body, if any, is passed as a series of calls to
|
The content-body, if any, is passed as a series of calls to
|
||||||
the write_body function. Transfer encodings are applied before
|
the write_body function. Transfer encodings are applied before
|
||||||
any data is passed to the write_body function.
|
any data is passed to the write_body function.
|
||||||
*/
|
*/
|
||||||
parser (std::function<void(void const*, std::size_t)> write_body,
|
parser(std::function<void(void const*, std::size_t)> write_body,
|
||||||
message& m, bool request)
|
message& m, bool request)
|
||||||
: beast::http::basic_parser (request)
|
: basic_parser(request)
|
||||||
, message_(m)
|
, m_(m)
|
||||||
, write_body_(std::move(write_body))
|
, write_body_(std::move(write_body))
|
||||||
{
|
{
|
||||||
message_.get().request(request);
|
m_.request(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser (message& m, body& b, bool request)
|
parser(message& m, body& b, bool request)
|
||||||
: beast::http::basic_parser (request)
|
: basic_parser(request)
|
||||||
, message_(m)
|
, m_(m)
|
||||||
{
|
{
|
||||||
write_body_ = [&b](void const* data, std::size_t size)
|
write_body_ = [&b](void const* data, std::size_t size)
|
||||||
{
|
{
|
||||||
b.write(data, size);
|
b.write(data, size);
|
||||||
};
|
};
|
||||||
|
m_.request(request);
|
||||||
message_.get().request(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser& operator= (parser&& other) = default;
|
//private:
|
||||||
|
|
||||||
private:
|
|
||||||
template <class = void>
|
|
||||||
void
|
void
|
||||||
do_start ();
|
on_start()
|
||||||
|
{
|
||||||
template <class = void>
|
}
|
||||||
bool
|
|
||||||
do_request (method_t method, std::string const& url,
|
void
|
||||||
int major, int minor, bool keep_alive, bool upgrade);
|
on_headers_complete(error_code&)
|
||||||
|
|
||||||
template <class = void>
|
|
||||||
bool
|
|
||||||
do_response (int status, std::string const& text,
|
|
||||||
int major, int minor, bool keep_alive, bool upgrade);
|
|
||||||
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
do_field (std::string const& field, std::string const& value);
|
|
||||||
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
do_body (void const* data, std::size_t bytes);
|
|
||||||
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
do_complete();
|
|
||||||
|
|
||||||
void
|
|
||||||
on_start () override
|
|
||||||
{
|
{
|
||||||
do_start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
on_request (method_t method, std::string const& url,
|
on_request(http::method_t method, std::string const& url,
|
||||||
int major, int minor, bool keep_alive, bool upgrade) override
|
int major, int minor, bool keep_alive, bool upgrade)
|
||||||
{
|
{
|
||||||
return do_request (method, url, major, minor, keep_alive, upgrade);
|
m_.method(method);
|
||||||
|
m_.url(url);
|
||||||
|
m_.version(major, minor);
|
||||||
|
m_.keep_alive(keep_alive);
|
||||||
|
m_.upgrade(upgrade);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
on_response (int status, std::string const& text,
|
on_response(int status, std::string const& text,
|
||||||
int major, int minor, bool keep_alive, bool upgrade) override
|
int major, int minor, bool keep_alive, bool upgrade)
|
||||||
{
|
{
|
||||||
return do_response (status, text, major, minor, keep_alive, upgrade);
|
m_.status(status);
|
||||||
|
m_.reason(text);
|
||||||
|
m_.version(major, minor);
|
||||||
|
m_.keep_alive(keep_alive);
|
||||||
|
m_.upgrade(upgrade);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_field (std::string const& field, std::string const& value) override
|
on_field(std::string const& field, std::string const& value)
|
||||||
{
|
{
|
||||||
do_field (field, value);
|
m_.headers.insert(field, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_body (void const* data, std::size_t bytes) override
|
on_body(void const* data, std::size_t bytes, error_code&)
|
||||||
{
|
{
|
||||||
do_body (data, bytes);
|
write_body_(data, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_complete() override
|
on_complete()
|
||||||
{
|
{
|
||||||
do_complete();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
} // deprecated_http
|
||||||
template <class>
|
|
||||||
void
|
|
||||||
parser::do_start()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
bool
|
|
||||||
parser::do_request (method_t method, std::string const& url,
|
|
||||||
int major, int minor, bool keep_alive, bool upgrade)
|
|
||||||
{
|
|
||||||
message_.get().method (method);
|
|
||||||
message_.get().url (url);
|
|
||||||
message_.get().version (major, minor);
|
|
||||||
message_.get().keep_alive (keep_alive);
|
|
||||||
message_.get().upgrade (upgrade);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
bool
|
|
||||||
parser::do_response (int status, std::string const& text,
|
|
||||||
int major, int minor, bool keep_alive, bool upgrade)
|
|
||||||
{
|
|
||||||
message_.get().status (status);
|
|
||||||
message_.get().reason (text);
|
|
||||||
message_.get().version (major, minor);
|
|
||||||
message_.get().keep_alive (keep_alive);
|
|
||||||
message_.get().upgrade (upgrade);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
void
|
|
||||||
parser::do_field (std::string const& field, std::string const& value)
|
|
||||||
{
|
|
||||||
message_.get().headers.append (field, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
void
|
|
||||||
parser::do_body (void const* data, std::size_t bytes)
|
|
||||||
{
|
|
||||||
write_body_(data, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class>
|
|
||||||
void
|
|
||||||
parser::do_complete()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
} // http
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
119
src/beast/beast/http/read.h
Normal file
119
src/beast/beast/http/read.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_READ_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_READ_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/error.h>
|
||||||
|
#include <beast/http/parser.h>
|
||||||
|
#include <beast/http/type_check.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/** Read a HTTP message from a stream.
|
||||||
|
|
||||||
|
@param stream The stream to read the message from.
|
||||||
|
|
||||||
|
@param streambuf A Streambuf used to hold unread bytes. The
|
||||||
|
implementation may read past the end of the message. The extra
|
||||||
|
bytes are stored here, to be presented in a subsequent call to
|
||||||
|
read.
|
||||||
|
|
||||||
|
@param msg An object used to store the read message. Any
|
||||||
|
contents will be overwritten.
|
||||||
|
|
||||||
|
@throws boost::system::system_error on failure.
|
||||||
|
*/
|
||||||
|
template<class SyncReadStream, class Streambuf,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||||
|
message<isRequest, Body, Headers>& msg)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
read(stream, streambuf, msg, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read a HTTP message from a stream.
|
||||||
|
|
||||||
|
@param stream The stream to read the message from.
|
||||||
|
|
||||||
|
@param streambuf A Streambuf used to hold unread bytes. The
|
||||||
|
implementation may read past the end of the message. The extra
|
||||||
|
bytes are stored here, to be presented in a subsequent call to
|
||||||
|
read.
|
||||||
|
|
||||||
|
@param msg An object used to store the read message. Any
|
||||||
|
contents will be overwritten.
|
||||||
|
|
||||||
|
@param ec Set to the error, if any occurred.
|
||||||
|
*/
|
||||||
|
template<class SyncReadStream, class Streambuf,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||||
|
message<isRequest, Body, Headers>& msg,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
|
/** Start reading a HTTP message from a stream asynchronously.
|
||||||
|
|
||||||
|
@param stream The stream to read the message from.
|
||||||
|
|
||||||
|
@param streambuf A Streambuf used to hold unread bytes. The
|
||||||
|
implementation may read past the end of the message. The extra
|
||||||
|
bytes are stored here, to be presented in a subsequent call to
|
||||||
|
async_read.
|
||||||
|
|
||||||
|
@param msg An object used to store the read message. Any
|
||||||
|
contents will be overwritten.
|
||||||
|
|
||||||
|
@param token The handler to be called when the request completes.
|
||||||
|
Copies will be made of the handler as required. The equivalent
|
||||||
|
function signature of the handler must be:
|
||||||
|
@code void handler(
|
||||||
|
error_code const& error // result of operation
|
||||||
|
); @endcode
|
||||||
|
Regardless of whether the asynchronous operation completes
|
||||||
|
immediately or not, the handler will not be invoked from within
|
||||||
|
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,
|
||||||
|
bool isRequest, class Body, class Headers,
|
||||||
|
class CompletionToken>
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
void_or_deduced
|
||||||
|
#else
|
||||||
|
auto
|
||||||
|
#endif
|
||||||
|
async_read(AsyncReadStream& stream, Streambuf& streambuf,
|
||||||
|
message<isRequest, Body, Headers>& msg,
|
||||||
|
CompletionToken&& token);
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/http/impl/read.ipp>
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,75 +1,32 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/*
|
/*
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
Copyright 2013: Vinnie Falco <vinnie.falco@gmail.com>
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
Permission to use: copy: modify: and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted: provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
copyright notice and this permission notice appear in all copies.
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
ANY SPECIAL : DIRECT: INDIRECT: OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE: DATA OR PROFITS: WHETHER IN AN
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
ACTION OF CONTRACT: NEGLIGENCE OR OTHER TORTIOUS ACTION: ARISING OUT OF
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/http/method.h>
|
#ifndef BEAST_HTTP_REASON_H_INCLUDED
|
||||||
#include <cassert>
|
#define BEAST_HTTP_REASON_H_INCLUDED
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
std::string
|
/** Returns the text for a known status code integer. */
|
||||||
to_string (method_t m)
|
template<class = void>
|
||||||
{
|
char const*
|
||||||
switch(m)
|
reason_string(int status)
|
||||||
{
|
|
||||||
case method_t::http_delete: return "DELETE";
|
|
||||||
case method_t::http_get: return "GET";
|
|
||||||
case method_t::http_head: return "HEAD";
|
|
||||||
case method_t::http_post: return "POST";
|
|
||||||
case method_t::http_put: return "PUT";
|
|
||||||
|
|
||||||
case method_t::http_connect: return "CONNECT";
|
|
||||||
case method_t::http_options: return "OPTIONS";
|
|
||||||
case method_t::http_trace: return "TRACE";
|
|
||||||
|
|
||||||
case method_t::http_copy: return "COPY";
|
|
||||||
case method_t::http_lock: return "LOCK";
|
|
||||||
case method_t::http_mkcol: return "MKCOL";
|
|
||||||
case method_t::http_move: return "MOVE";
|
|
||||||
case method_t::http_propfind: return "PROPFIND";
|
|
||||||
case method_t::http_proppatch: return "PROPPATCH";
|
|
||||||
case method_t::http_search: return "SEARCH";
|
|
||||||
case method_t::http_unlock: return "UNLOCK";
|
|
||||||
|
|
||||||
case method_t::http_report: return "REPORT";
|
|
||||||
case method_t::http_mkactivity: return "MKACTIVITY";
|
|
||||||
case method_t::http_checkout: return "CHECKOUT";
|
|
||||||
case method_t::http_merge: return "MERGE";
|
|
||||||
|
|
||||||
case method_t::http_msearch: return "MSEARCH";
|
|
||||||
case method_t::http_notify: return "NOTIFY";
|
|
||||||
case method_t::http_subscribe: return "SUBSCRIBE";
|
|
||||||
case method_t::http_unsubscribe: return "UNSUBSCRIBE";
|
|
||||||
|
|
||||||
case method_t::http_patch: return "PATCH";
|
|
||||||
case method_t::http_purge: return "PURGE";
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
return "GET";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
status_text (int status)
|
|
||||||
{
|
{
|
||||||
switch(status)
|
switch(status)
|
||||||
{
|
{
|
||||||
@@ -88,7 +45,6 @@ status_text (int status)
|
|||||||
case 303: return "See Other";
|
case 303: return "See Other";
|
||||||
case 304: return "Not Modified";
|
case 304: return "Not Modified";
|
||||||
case 305: return "Use Proxy";
|
case 305: return "Use Proxy";
|
||||||
//case 306: return "<reserved>";
|
|
||||||
case 307: return "Temporary Redirect";
|
case 307: return "Temporary Redirect";
|
||||||
case 400: return "Bad Request";
|
case 400: return "Bad Request";
|
||||||
case 401: return "Unauthorized";
|
case 401: return "Unauthorized";
|
||||||
@@ -114,11 +70,15 @@ status_text (int status)
|
|||||||
case 503: return "Service Unavailable";
|
case 503: return "Service Unavailable";
|
||||||
case 504: return "Gateway Timeout";
|
case 504: return "Gateway Timeout";
|
||||||
case 505: return "HTTP Version Not Supported";
|
case 505: return "HTTP Version Not Supported";
|
||||||
|
|
||||||
|
case 306: return "<reserved>";
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return "Unknown HTTP status";
|
return "<unknown-status>";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // http
|
||||||
}
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -17,47 +17,30 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_DETAIL_HEADER_TRAITS_H_INCLUDED
|
#ifndef BEAST_HTTP_RESUME_CONTEXT_H_INCLUDED
|
||||||
#define BEAST_HTTP_DETAIL_HEADER_TRAITS_H_INCLUDED
|
#define BEAST_HTTP_RESUME_CONTEXT_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/utility/ci_char_traits.h>
|
#include <functional>
|
||||||
|
|
||||||
#include <boost/utility/string_ref.hpp>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
// Utilities for dealing with HTTP headers
|
/** A functor that resumes a write operation.
|
||||||
|
|
||||||
template <class Allocator = std::allocator <char>>
|
An rvalue reference to an object of this type is provided by the
|
||||||
using basic_field_string =
|
write implementation to the `writer` associated with the body of
|
||||||
std::basic_string <char, ci_char_traits, Allocator>;
|
a message being sent.
|
||||||
|
|
||||||
using field_string = basic_field_string <>;
|
If it is desired that the `writer` suspend the write operation (for
|
||||||
|
example, to wait until data is ready), it can take ownership of
|
||||||
using field_string_ref = boost::basic_string_ref <char, ci_char_traits>;
|
the resume context using a move. Then, it returns `boost::indeterminate`
|
||||||
|
to indicate that the write operation should suspend. Later, the calling
|
||||||
/** Returns `true` if two header fields are the same.
|
code invokes the resume function and the write operation continues
|
||||||
The comparison is case-insensitive.
|
from where it left off.
|
||||||
*/
|
*/
|
||||||
template <class Alloc1, class Alloc2>
|
using resume_context = std::function<void(void)>;
|
||||||
inline
|
|
||||||
bool field_eq (
|
|
||||||
std::basic_string <char, std::char_traits <char>, Alloc1> const& s1,
|
|
||||||
std::basic_string <char, std::char_traits <char>, Alloc2> const& s2)
|
|
||||||
{
|
|
||||||
return field_string_ref (s1.c_str(), s1.size()) ==
|
|
||||||
field_string_ref (s2.c_str(), s2.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the string with leading and trailing LWS removed. */
|
} // http
|
||||||
|
} // beast
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -20,10 +20,14 @@
|
|||||||
#ifndef BEAST_HTTP_RFC2616_H_INCLUDED
|
#ifndef BEAST_HTTP_RFC2616_H_INCLUDED
|
||||||
#define BEAST_HTTP_RFC2616_H_INCLUDED
|
#define BEAST_HTTP_RFC2616_H_INCLUDED
|
||||||
|
|
||||||
#include <boost/regex.hpp>
|
#include <boost/range/algorithm/equal.hpp>
|
||||||
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
#include <boost/utility/string_ref.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <tuple> // for std::tie, remove ASAP
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -36,20 +40,34 @@ namespace beast {
|
|||||||
*/
|
*/
|
||||||
namespace 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.
|
/** Returns `true` if `c` is linear white space.
|
||||||
|
|
||||||
This excludes the CRLF sequence allowed for line continuations.
|
This excludes the CRLF sequence allowed for line continuations.
|
||||||
*/
|
*/
|
||||||
template <class CharT>
|
inline
|
||||||
bool
|
bool
|
||||||
is_lws (CharT c)
|
is_lws(char c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t';
|
return c == ' ' || c == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns `true` if `c` is any whitespace character. */
|
/** Returns `true` if `c` is any whitespace character. */
|
||||||
template <class CharT>
|
inline
|
||||||
bool
|
bool
|
||||||
is_white (CharT c)
|
is_white(char c)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
@@ -61,18 +79,19 @@ is_white (CharT c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns `true` if `c` is a control character. */
|
/** Returns `true` if `c` is a control character. */
|
||||||
template <class CharT>
|
inline
|
||||||
bool
|
bool
|
||||||
is_ctl (CharT c)
|
is_control(char c)
|
||||||
{
|
{
|
||||||
return c <= 31 || c >= 127;
|
return c <= 31 || c >= 127;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns `true` if `c` is a separator. */
|
/** Returns `true` if `c` is a separator. */
|
||||||
template <class CharT>
|
inline
|
||||||
bool
|
bool
|
||||||
is_sep (CharT c)
|
is_separator(char c)
|
||||||
{
|
{
|
||||||
|
// VFALCO Could use a static table
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '(': case ')': case '<': case '>': case '@':
|
case '(': case ')': case '<': case '>': case '@':
|
||||||
@@ -83,12 +102,20 @@ is_sep (CharT c)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns `true` if `c` is a character. */
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
is_char(char c)
|
||||||
|
{
|
||||||
|
return c >= 0 && c <= 127;
|
||||||
|
}
|
||||||
|
|
||||||
template <class FwdIter>
|
template <class FwdIter>
|
||||||
FwdIter
|
FwdIter
|
||||||
trim_left (FwdIter first, FwdIter last)
|
trim_left (FwdIter first, FwdIter last)
|
||||||
{
|
{
|
||||||
return std::find_if_not (first, last,
|
return std::find_if_not (first, last,
|
||||||
&is_white <typename FwdIter::value_type>);
|
is_white);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FwdIter>
|
template <class FwdIter>
|
||||||
@@ -166,8 +193,9 @@ trim (std::string const& s)
|
|||||||
*/
|
*/
|
||||||
template <class FwdIt,
|
template <class FwdIt,
|
||||||
class Result = std::vector<
|
class Result = std::vector<
|
||||||
std::basic_string<typename FwdIt::value_type>>,
|
std::basic_string<typename
|
||||||
class Char>
|
std::iterator_traits<FwdIt>::value_type>>,
|
||||||
|
class Char>
|
||||||
Result
|
Result
|
||||||
split(FwdIt first, FwdIt last, Char delim)
|
split(FwdIt first, FwdIt last, Char delim)
|
||||||
{
|
{
|
||||||
@@ -239,7 +267,8 @@ split(FwdIt first, FwdIt last, Char delim)
|
|||||||
|
|
||||||
template <class FwdIt,
|
template <class FwdIt,
|
||||||
class Result = std::vector<
|
class Result = std::vector<
|
||||||
std::basic_string<typename FwdIt::value_type>>>
|
std::basic_string<typename std::iterator_traits<
|
||||||
|
FwdIt>::value_type>>>
|
||||||
Result
|
Result
|
||||||
split_commas(FwdIt first, FwdIt last)
|
split_commas(FwdIt first, FwdIt last)
|
||||||
{
|
{
|
||||||
@@ -248,11 +277,194 @@ split_commas(FwdIt first, FwdIt last)
|
|||||||
|
|
||||||
template <class Result = std::vector<std::string>>
|
template <class Result = std::vector<std::string>>
|
||||||
Result
|
Result
|
||||||
split_commas(std::string const& s)
|
split_commas(boost::string_ref const& s)
|
||||||
{
|
{
|
||||||
return split_commas(s.begin(), s.end());
|
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
|
||||||
|
auto
|
||||||
|
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
|
} // rfc2616
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|||||||
@@ -17,13 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/http/impl/joyent_parser.h>
|
#include <beast/http/src/nodejs_parser.h>
|
||||||
#include <beast/http/method.h>
|
#include <beast/http/method.h>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace joyent {
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning (push)
|
# pragma warning (push)
|
||||||
# pragma warning (disable: 4127) // conditional expression is constant
|
# pragma warning (disable: 4127) // conditional expression is constant
|
||||||
@@ -34,33 +31,10 @@ namespace joyent {
|
|||||||
# pragma warning (pop)
|
# pragma warning (pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
beast::http::method_t
|
||||||
}
|
convert_http_method(http_method m)
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace system {
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct is_error_code_enum <beast::joyent::http_errno>
|
|
||||||
: std::true_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct is_error_condition_enum <beast::joyent::http_errno>
|
|
||||||
: std::true_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace joyent {
|
|
||||||
|
|
||||||
http::method_t
|
|
||||||
convert_http_method (joyent::http_method m)
|
|
||||||
{
|
{
|
||||||
|
using namespace beast;
|
||||||
switch (m)
|
switch (m)
|
||||||
{
|
{
|
||||||
case HTTP_DELETE: return http::method_t::http_delete;
|
case HTTP_DELETE: return http::method_t::http_delete;
|
||||||
@@ -114,58 +88,3 @@ convert_http_method (joyent::http_method m)
|
|||||||
|
|
||||||
return http::method_t::http_get;
|
return http::method_t::http_get;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::system::error_code
|
|
||||||
convert_http_errno (joyent::http_errno err)
|
|
||||||
{
|
|
||||||
class http_error_category_t
|
|
||||||
: public boost::system::error_category
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using error_code = boost::system::error_code;
|
|
||||||
using error_condition = boost::system::error_condition;
|
|
||||||
|
|
||||||
public:
|
|
||||||
char const*
|
|
||||||
name() const noexcept override
|
|
||||||
{
|
|
||||||
return "http_errno";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
message (int ev) const override
|
|
||||||
{
|
|
||||||
return joyent::http_errno_name (
|
|
||||||
joyent::http_errno (ev));
|
|
||||||
}
|
|
||||||
|
|
||||||
error_condition
|
|
||||||
default_error_condition (int ev) const noexcept override
|
|
||||||
{
|
|
||||||
return error_condition (ev, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
equivalent (int code, error_condition const& condition
|
|
||||||
) const noexcept override
|
|
||||||
{
|
|
||||||
return default_error_condition (code) == condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
equivalent (error_code const& code, int condition
|
|
||||||
) const noexcept override
|
|
||||||
{
|
|
||||||
return *this == code.category() &&
|
|
||||||
code.value() == condition;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static http_error_category_t http_error_category;
|
|
||||||
|
|
||||||
return boost::system::error_code (
|
|
||||||
err, http_error_category);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,28 +17,29 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_JOYENT_PARSER_H_INCLUDED
|
#ifndef BEAST_HTTP_NODEJS_PARSER_H_INCLUDED
|
||||||
#define BEAST_HTTP_JOYENT_PARSER_H_INCLUDED
|
#define BEAST_HTTP_NODEJS_PARSER_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/http/method.h>
|
#include <beast/http/method.h>
|
||||||
|
#include <beast/http/impl/http-parser/http_parser.h>
|
||||||
// TODO Use <system_error>
|
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
// Wraps the C-language joyent http parser header in a namespace
|
beast::http::method_t
|
||||||
|
convert_http_method(http_method m);
|
||||||
|
|
||||||
namespace beast {
|
namespace boost {
|
||||||
namespace joyent {
|
namespace system {
|
||||||
|
template<>
|
||||||
#include <beast/http/impl/http-parser/http_parser.h>
|
struct is_error_code_enum<http_errno>
|
||||||
|
: std::true_type
|
||||||
http::method_t
|
{
|
||||||
convert_http_method (joyent::http_method m);
|
};
|
||||||
|
template<>
|
||||||
boost::system::error_code
|
struct is_error_condition_enum<http_errno>
|
||||||
convert_http_errno (joyent::http_errno err);
|
: std::true_type
|
||||||
|
{
|
||||||
}
|
};
|
||||||
}
|
} // system
|
||||||
|
} // boost
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
186
src/beast/beast/http/src/test/beast_http_message_test.cpp
Normal file
186
src/beast/beast/http/src/test/beast_http_message_test.cpp
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <beast/unit_test/thread.h>
|
||||||
|
#include <beast/asio/buffers_debug.h>
|
||||||
|
#include <beast/asio/placeholders.h>
|
||||||
|
#include <beast/asio/streambuf.h>
|
||||||
|
#include <beast/http.h>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class sync_echo_http_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using error_code = boost::system::error_code;
|
||||||
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
|
using address_type = boost::asio::ip::address;
|
||||||
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
|
private:
|
||||||
|
unit_test::suite& suite_;
|
||||||
|
boost::asio::io_service ios_;
|
||||||
|
socket_type sock_;
|
||||||
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
|
unit_test::thread thread_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
sync_echo_http_server(
|
||||||
|
endpoint_type ep, unit_test::suite& suite)
|
||||||
|
: suite_(suite)
|
||||||
|
, sock_(ios_)
|
||||||
|
, acceptor_(ios_)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
acceptor_.open(ep.protocol(), ec);
|
||||||
|
maybe_throw(ec, "open");
|
||||||
|
acceptor_.bind(ep, ec);
|
||||||
|
maybe_throw(ec, "bind");
|
||||||
|
acceptor_.listen(
|
||||||
|
boost::asio::socket_base::max_connections, ec);
|
||||||
|
maybe_throw(ec, "listen");
|
||||||
|
acceptor_.async_accept(sock_,
|
||||||
|
std::bind(&sync_echo_http_server::on_accept, this,
|
||||||
|
beast::asio::placeholders::error));
|
||||||
|
thread_ = unit_test::thread(suite_,
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
ios_.run();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
~sync_echo_http_server()
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ios_.dispatch(
|
||||||
|
[&]{ acceptor_.close(ec); });
|
||||||
|
thread_.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
fail(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
suite_.log <<
|
||||||
|
what << ": " << ec.message();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
maybe_throw(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
if(ec &&
|
||||||
|
ec != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
fail(ec, what);
|
||||||
|
throw ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_accept(error_code ec)
|
||||||
|
{
|
||||||
|
if(ec == boost::asio::error::operation_aborted)
|
||||||
|
return;
|
||||||
|
maybe_throw(ec, "accept");
|
||||||
|
std::thread{&sync_echo_http_server::do_client, this,
|
||||||
|
std::move(sock_), boost::asio::io_service::work{
|
||||||
|
sock_.get_io_service()}}.detach();
|
||||||
|
acceptor_.async_accept(sock_,
|
||||||
|
std::bind(&sync_echo_http_server::on_accept, this,
|
||||||
|
beast::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
do_client(socket_type sock, boost::asio::io_service::work)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
streambuf rb;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
request<string_body> req;
|
||||||
|
read(sock, rb, req, ec);
|
||||||
|
if(ec)
|
||||||
|
break;
|
||||||
|
response<string_body> resp(
|
||||||
|
{100, "OK", req.version});
|
||||||
|
resp.body = "Completed successfully.";
|
||||||
|
write(sock, resp, ec);
|
||||||
|
if(ec)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class http_message_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using error_code = boost::system::error_code;
|
||||||
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
|
using address_type = boost::asio::ip::address;
|
||||||
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
|
void
|
||||||
|
syncEcho(endpoint_type ep)
|
||||||
|
{
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
socket_type sock(ios);
|
||||||
|
sock.connect(ep);
|
||||||
|
|
||||||
|
streambuf rb;
|
||||||
|
{
|
||||||
|
request<string_body> req(
|
||||||
|
{beast::http::method_t::http_get, "/", 11});
|
||||||
|
req.body = "Beast.HTTP";
|
||||||
|
req.headers.replace("Host",
|
||||||
|
ep.address().to_string() + ":" +
|
||||||
|
std::to_string(ep.port()));
|
||||||
|
write(sock, req);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
response<string_body> m;
|
||||||
|
read(sock, rb, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testAsio()
|
||||||
|
{
|
||||||
|
endpoint_type ep{
|
||||||
|
address_type::from_string("127.0.0.1"), 6000};
|
||||||
|
sync_echo_http_server s(ep, *this);
|
||||||
|
syncEcho(ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testAsio();
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE_MANUAL(http_message,http,beast);
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
@@ -23,46 +23,30 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace deprecated_http {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
class message_test : public beast::unit_test::suite
|
class parser_test : public beast::unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::pair <message, bool>
|
message
|
||||||
request (std::string const& text)
|
request(std::string const& text)
|
||||||
{
|
{
|
||||||
message m;
|
|
||||||
body b;
|
body b;
|
||||||
parser p (m, b, true);
|
message m;
|
||||||
auto result (p.write (boost::asio::buffer(text)));
|
parser p(m, b, true);
|
||||||
|
auto const used =
|
||||||
|
p.write(boost::asio::buffer(text));
|
||||||
|
expect(used == text.size());
|
||||||
p.write_eof();
|
p.write_eof();
|
||||||
return std::make_pair (std::move(m), result.first);
|
return m;
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
dump()
|
|
||||||
{
|
|
||||||
auto const result = request (
|
|
||||||
"GET / HTTP/1.1\r\n"
|
|
||||||
//"Connection: Upgrade\r\n"
|
|
||||||
//"Upgrade: Ripple\r\n"
|
|
||||||
"Field: \t Value \t \r\n"
|
|
||||||
"Blib: Continu\r\n"
|
|
||||||
" ation\r\n"
|
|
||||||
"Field: Hey\r\n"
|
|
||||||
"Content-Length: 1\r\n"
|
|
||||||
"\r\n"
|
|
||||||
"x"
|
|
||||||
);
|
|
||||||
log << result.first.headers;
|
|
||||||
log << "|" << result.first.headers["Field"] << "|";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
test_headers()
|
test_headers()
|
||||||
{
|
{
|
||||||
headers h;
|
beast::http::headers<std::allocator<char>> h;
|
||||||
h.append("Field", "Value");
|
h.insert("Field", "Value");
|
||||||
expect (h.erase("Field") == 1);
|
expect (h.erase("Field") == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,14 +60,14 @@ public:
|
|||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
;
|
;
|
||||||
message m;
|
|
||||||
body b;
|
body b;
|
||||||
|
message m;
|
||||||
parser p (m, b, true);
|
parser p (m, b, true);
|
||||||
auto result (p.write (boost::asio::buffer(text)));
|
auto const used = p.write(
|
||||||
expect (! result.first);
|
boost::asio::buffer(text));
|
||||||
auto result2 (p.write_eof());
|
expect(used == text.size());
|
||||||
expect (! result2);
|
p.write_eof();
|
||||||
expect (p.complete());
|
expect(p.complete());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -92,17 +76,19 @@ public:
|
|||||||
"GET\r\n"
|
"GET\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
;
|
;
|
||||||
message m;
|
|
||||||
body b;
|
body b;
|
||||||
parser p (m, b, true);
|
message m;
|
||||||
auto result = p.write (boost::asio::buffer(text));
|
parser p(m, b, true);
|
||||||
if (expect (result.first))
|
boost::system::error_code ec;
|
||||||
expect (result.first.message() == "invalid HTTP method");
|
p.write(boost::asio::buffer(text), ec);
|
||||||
|
if(expect(ec))
|
||||||
|
expect(ec.message() == "invalid HTTP method");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(message,http,beast);
|
BEAST_DEFINE_TESTSUITE(parser,http,beast);
|
||||||
|
|
||||||
} // http
|
} // test
|
||||||
|
} // deprecated_http
|
||||||
} // beast
|
} // beast
|
||||||
126
src/beast/beast/http/src/test/beast_http_rfc2616_test.cpp
Normal file
126
src/beast/beast/http/src/test/beast_http_rfc2616_test.cpp
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <beast/http/rfc2616.h>
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#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
|
||||||
109
src/beast/beast/http/streambuf_body.h
Normal file
109
src/beast/beast/http/streambuf_body.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_STREAMBUF_BODY_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_STREAMBUF_BODY_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/error.h>
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <beast/asio/append_buffers.h>
|
||||||
|
#include <beast/asio/streambuf.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/** A Body represented by a Streambuf
|
||||||
|
*/
|
||||||
|
template<class Streambuf>
|
||||||
|
struct basic_streambuf_body
|
||||||
|
{
|
||||||
|
using value_type = Streambuf;
|
||||||
|
|
||||||
|
class reader
|
||||||
|
{
|
||||||
|
value_type& sb_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<bool isRequest, class Allocator>
|
||||||
|
explicit
|
||||||
|
reader(message<isRequest,
|
||||||
|
basic_streambuf_body, Allocator>& 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:
|
||||||
|
template<bool isRequest, class Allocator>
|
||||||
|
explicit
|
||||||
|
writer(message<isRequest, basic_streambuf_body,
|
||||||
|
Allocator> const& m)
|
||||||
|
: body_(m.body)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
init(error_code& ec)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
content_length() const
|
||||||
|
{
|
||||||
|
return body_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Write>
|
||||||
|
boost::tribool
|
||||||
|
operator()(resume_context&&, error_code&, Write&& write)
|
||||||
|
{
|
||||||
|
write(body_.data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
data() const noexcept
|
||||||
|
{
|
||||||
|
return body_.data();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
using streambuf_body = basic_streambuf_body<streambuf>;
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
99
src/beast/beast/http/string_body.h
Normal file
99
src/beast/beast/http/string_body.h
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_STRING_BODY_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_STRING_BODY_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/error.h>
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <beast/http/resume_context.h>
|
||||||
|
#include <beast/asio/append_buffers.h>
|
||||||
|
#include <beast/asio/streambuf.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/** A Body represented by a std::string.
|
||||||
|
*/
|
||||||
|
struct string_body
|
||||||
|
{
|
||||||
|
using value_type = std::string;
|
||||||
|
|
||||||
|
class reader
|
||||||
|
{
|
||||||
|
value_type& s_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<bool isRequest, class Allocator>
|
||||||
|
explicit
|
||||||
|
reader(message<isRequest,
|
||||||
|
string_body, Allocator>& m) noexcept
|
||||||
|
: s_(m.body)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
write(void const* data,
|
||||||
|
std::size_t size, error_code&) noexcept
|
||||||
|
{
|
||||||
|
auto const n = s_.size();
|
||||||
|
s_.resize(n + size);
|
||||||
|
std::memcpy(&s_[n], data, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class writer
|
||||||
|
{
|
||||||
|
value_type const& body_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<bool isRequest, class Allocator>
|
||||||
|
explicit
|
||||||
|
writer(message<isRequest, string_body, Allocator> const& msg)
|
||||||
|
: body_(msg.body)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
init(error_code& ec)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
content_length() const
|
||||||
|
{
|
||||||
|
return body_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Write>
|
||||||
|
boost::tribool
|
||||||
|
operator()(resume_context&&, error_code&, Write&& write)
|
||||||
|
{
|
||||||
|
write(boost::asio::buffer(body_));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#if BEAST_INCLUDE_BEASTCONFIG
|
|
||||||
#include "../../BeastConfig.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <beast/http/rfc2616.h>
|
|
||||||
#include <beast/unit_test/suite.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace rfc2616 {
|
|
||||||
|
|
||||||
class rfc2616_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void
|
|
||||||
check (std::string const& s,
|
|
||||||
std::vector <std::string> const& expected)
|
|
||||||
{
|
|
||||||
auto const parsed = split_commas(s.begin(), s.end());
|
|
||||||
expect (parsed == expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_split_commas()
|
|
||||||
{
|
|
||||||
testcase("split_commas");
|
|
||||||
check ("", {});
|
|
||||||
check (" ", {});
|
|
||||||
check (" ", {});
|
|
||||||
check ("\t", {});
|
|
||||||
check (" \t ", {});
|
|
||||||
check (",", {});
|
|
||||||
check (",,", {});
|
|
||||||
check (" ,", {});
|
|
||||||
check (" , ,", {});
|
|
||||||
check ("x", {"x"});
|
|
||||||
check (" x", {"x"});
|
|
||||||
check (" \t x", {"x"});
|
|
||||||
check ("x ", {"x"});
|
|
||||||
check ("x \t", {"x"});
|
|
||||||
check (" \t x \t ", {"x"});
|
|
||||||
check ("\"\"", {});
|
|
||||||
check (" \"\"", {});
|
|
||||||
check ("\"\" ", {});
|
|
||||||
check ("\"x\"", {"x"});
|
|
||||||
check ("\" \"", {" "});
|
|
||||||
check ("\" x\"", {" x"});
|
|
||||||
check ("\"x \"", {"x "});
|
|
||||||
check ("\" x \"", {" x "});
|
|
||||||
check ("\"\tx \"", {"\tx "});
|
|
||||||
check ("x,y", { "x", "y" });
|
|
||||||
check ("x ,\ty ", { "x", "y" });
|
|
||||||
check ("x, y, z", {"x","y","z"});
|
|
||||||
check ("x, \"y\", z", {"x","y","z"});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
run()
|
|
||||||
{
|
|
||||||
test_split_commas();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(rfc2616,http,beast);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
84
src/beast/beast/http/type_check.h
Normal file
84
src/beast/beast/http/type_check.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_TYPE_CHECK_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_TYPE_CHECK_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/error.h>
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <beast/http/resume_context.h>
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/logic/tribool.hpp>
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
#include <functional>
|
||||||
|
#include <beast/cxx17/type_traits.h> // <type_traits>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
namespace detail {
|
||||||
|
#else
|
||||||
|
namespace concept {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Reader
|
||||||
|
{
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
Reader(message<isRequest, Body, Headers>&) noexcept;
|
||||||
|
void write(void const*, std::size_t, error_code&) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // concept
|
||||||
|
|
||||||
|
/// Evaluates to std::true_type if `T` models Body
|
||||||
|
template<class T>
|
||||||
|
struct is_Body : std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Evalulates to std::true_type if Body has a reader
|
||||||
|
template<class T>
|
||||||
|
struct is_ReadableBody : std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Evalulates to std::true_type if Body has a writer
|
||||||
|
template<class T>
|
||||||
|
struct is_WritableBody : std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Evaluates to std::true_type if `T` models HTTPMessage
|
||||||
|
template<class T>
|
||||||
|
struct is_HTTPMessage : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Evaluates to std::true_type if `HTTPMessage` is a request
|
||||||
|
template<class HTTPMessage>
|
||||||
|
struct is_HTTPRequest : std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
103
src/beast/beast/http/write.h
Normal file
103
src/beast/beast/http/write.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_WRITE_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_WRITE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/error.h>
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/** Write a HTTP message to a stream.
|
||||||
|
|
||||||
|
@param stream The stream to send the message on.
|
||||||
|
|
||||||
|
@param msg The message to send.
|
||||||
|
|
||||||
|
@throws boost::system::error code on failure.
|
||||||
|
*/
|
||||||
|
template<class SyncWriteStream,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
write(SyncWriteStream& stream,
|
||||||
|
message<isRequest, Body, Headers> const& msg)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
write(stream, msg, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write a HTTP message to a stream.
|
||||||
|
|
||||||
|
@param stream The stream to send the message on.
|
||||||
|
|
||||||
|
@param msg The message to send.
|
||||||
|
|
||||||
|
@param ec Set to the error, if any occurred.
|
||||||
|
*/
|
||||||
|
template<class SyncWriteStream,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
write(SyncWriteStream& stream,
|
||||||
|
message<isRequest, Body, Headers> const& msg,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
|
/** Start writing a HTTP message to a stream asynchronously.
|
||||||
|
|
||||||
|
@param stream The stream to send the message on.
|
||||||
|
|
||||||
|
@param msg The message to send.
|
||||||
|
|
||||||
|
@param token The handler to be called when the request completes.
|
||||||
|
Copies will be made of the handler as required. The equivalent
|
||||||
|
function signature of the handler must be:
|
||||||
|
@code void handler(
|
||||||
|
error_code const& error // result of operation
|
||||||
|
); @endcode
|
||||||
|
Regardless of whether the asynchronous operation completes
|
||||||
|
immediately or not, the handler will not be invoked from within
|
||||||
|
this function. Invocation of the handler will be performed in a
|
||||||
|
manner equivalent to using boost::asio::io_service::post().
|
||||||
|
|
||||||
|
@note The message must remain valid at least until the
|
||||||
|
completion handler is called, no copies are made.
|
||||||
|
*/
|
||||||
|
template<class AsyncWriteStream,
|
||||||
|
bool isRequest, class Body, class Headers,
|
||||||
|
class CompletionToken>
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
void_or_deduced
|
||||||
|
#else
|
||||||
|
auto
|
||||||
|
#endif
|
||||||
|
async_write(AsyncWriteStream& stream,
|
||||||
|
message<isRequest, Body, Headers> const& msg,
|
||||||
|
CompletionToken&& token);
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/http/impl/write.ipp>
|
||||||
|
|
||||||
|
#endif
|
||||||
27
src/beast/beast/unity/beast_http_unity.cpp
Normal file
27
src/beast/beast/unity/beast_http_unity.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <beast/http/src/test/beast_http_chunked_encoder_test.cpp>
|
||||||
|
#include <beast/http/src/test/beast_http_message_test.cpp>
|
||||||
|
#include <beast/http/src/test/beast_http_parser_test.cpp>
|
||||||
|
#include <beast/http/src/test/beast_http_rfc2616_test.cpp>
|
||||||
|
|
||||||
|
// VFALCO Must come last otherwise Windows 10 SDK
|
||||||
|
// gets a compile error in winnt.h
|
||||||
|
#include <beast/http/src/beast_http_nodejs_parser.cpp>
|
||||||
19
src/beast/examples/Jamfile
Normal file
19
src/beast/examples/Jamfile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#
|
||||||
|
# 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)
|
||||||
|
#
|
||||||
|
|
||||||
|
import os ;
|
||||||
|
|
||||||
|
exe http_crawl :
|
||||||
|
../beast/http/src/beast_http_nodejs_parser.cpp
|
||||||
|
http_crawl.cpp
|
||||||
|
urls_large_data.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
exe http_server :
|
||||||
|
../beast/http/src/beast_http_nodejs_parser.cpp
|
||||||
|
http_server.cpp
|
||||||
|
;
|
||||||
94
src/beast/examples/file_body.h
Normal file
94
src/beast/examples/file_body.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||||
|
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <beast/http/resume_context.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
struct file_body
|
||||||
|
{
|
||||||
|
using value_type = std::string;
|
||||||
|
|
||||||
|
class writer
|
||||||
|
{
|
||||||
|
std::size_t size_;
|
||||||
|
std::size_t offset_ = 0;
|
||||||
|
std::string const& path_;
|
||||||
|
FILE* file_ = nullptr;
|
||||||
|
char buf_[4096];
|
||||||
|
std::size_t buf_len_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool constexpr is_single_pass = false;
|
||||||
|
|
||||||
|
template<bool isRequest, class Headers>
|
||||||
|
writer(message<isRequest, file_body, Headers> const& m) noexcept
|
||||||
|
: path_(m.body)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~writer()
|
||||||
|
{
|
||||||
|
if(file_)
|
||||||
|
fclose(file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
init(error_code& ec) noexcept
|
||||||
|
{
|
||||||
|
file_ = fopen(path_.c_str(), "rb");
|
||||||
|
if(! file_)
|
||||||
|
ec = boost::system::errc::make_error_code(
|
||||||
|
static_cast<boost::system::errc::errc_t>(errno));
|
||||||
|
else
|
||||||
|
size_ = boost::filesystem::file_size(path_);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
content_length() const
|
||||||
|
{
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Write>
|
||||||
|
boost::tribool
|
||||||
|
operator()(resume_context&&, error_code&, Write&& write)
|
||||||
|
{
|
||||||
|
buf_len_ = std::min(size_ - offset_, sizeof(buf_));
|
||||||
|
fread(buf_, 1, sizeof(buf_), file_);
|
||||||
|
offset_ += buf_len_;
|
||||||
|
write(boost::asio::buffer(buf_, buf_len_));
|
||||||
|
return offset_ >= size_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
205
src/beast/examples/http_async_server.h
Normal file
205
src/beast/examples/http_async_server.h
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
||||||
|
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
||||||
|
|
||||||
|
#include "file_body.h"
|
||||||
|
#include "http_stream.h"
|
||||||
|
|
||||||
|
#include <beast/asio/placeholders.h>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
class http_async_server
|
||||||
|
{
|
||||||
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
|
using address_type = boost::asio::ip::address;
|
||||||
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
|
using req_type = request<string_body>;
|
||||||
|
using resp_type = response<file_body>;
|
||||||
|
|
||||||
|
boost::asio::io_service ios_;
|
||||||
|
socket_type sock_;
|
||||||
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
|
std::string root_;
|
||||||
|
std::vector<std::thread> thread_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
http_async_server(endpoint_type const& ep,
|
||||||
|
int threads, std::string const& root)
|
||||||
|
: sock_(ios_)
|
||||||
|
, acceptor_(ios_)
|
||||||
|
, root_(root)
|
||||||
|
{
|
||||||
|
acceptor_.open(ep.protocol());
|
||||||
|
acceptor_.bind(ep);
|
||||||
|
acceptor_.listen(
|
||||||
|
boost::asio::socket_base::max_connections);
|
||||||
|
acceptor_.async_accept(sock_,
|
||||||
|
std::bind(&http_async_server::on_accept, this,
|
||||||
|
beast::asio::placeholders::error));
|
||||||
|
thread_.reserve(threads);
|
||||||
|
for(int i = 0; i < threads; ++i)
|
||||||
|
thread_.emplace_back(
|
||||||
|
[&] { ios_.run(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
~http_async_server()
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ios_.dispatch(
|
||||||
|
[&]{ acceptor_.close(ec); });
|
||||||
|
for(auto& t : thread_)
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class peer : public std::enable_shared_from_this<peer>
|
||||||
|
{
|
||||||
|
int id_;
|
||||||
|
stream<socket_type> stream_;
|
||||||
|
boost::asio::io_service::strand strand_;
|
||||||
|
std::string root_;
|
||||||
|
req_type req_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
peer(peer&&) = default;
|
||||||
|
peer(peer const&) = default;
|
||||||
|
peer& operator=(peer&&) = delete;
|
||||||
|
peer& operator=(peer const&) = delete;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
peer(socket_type&& sock, std::string const& root)
|
||||||
|
: id_([]
|
||||||
|
{
|
||||||
|
static int n = 0;
|
||||||
|
return ++n;
|
||||||
|
}())
|
||||||
|
, stream_(std::move(sock))
|
||||||
|
, strand_(stream_.get_io_service())
|
||||||
|
, root_(root)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
do_read();
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_read()
|
||||||
|
{
|
||||||
|
stream_.async_read(req_, strand_.wrap(
|
||||||
|
std::bind(&peer::on_read, shared_from_this(),
|
||||||
|
asio::placeholders::error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_read(error_code ec)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
return fail(ec, "read");
|
||||||
|
do_read();
|
||||||
|
auto path = req_.url;
|
||||||
|
if(path == "/")
|
||||||
|
path = "/index.html";
|
||||||
|
path = root_ + path;
|
||||||
|
if(! boost::filesystem::exists(path))
|
||||||
|
{
|
||||||
|
response<string_body> resp(
|
||||||
|
{404, "Not Found", req_.version});
|
||||||
|
resp.headers.replace("Server", "http_async_server");
|
||||||
|
resp.body = "The file '" + path + "' was not found";
|
||||||
|
stream_.async_write(std::move(resp),
|
||||||
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
|
asio::placeholders::error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response<file_body> resp(
|
||||||
|
{200, "OK", req_.version});
|
||||||
|
resp.headers.replace("Server", "http_async_server");
|
||||||
|
resp.headers.replace("Content-Type", "text/html");
|
||||||
|
resp.body = path;
|
||||||
|
stream_.async_write(std::move(resp),
|
||||||
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
|
asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_write(error_code ec)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
fail(ec, "write");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
fail(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
std::cerr <<
|
||||||
|
"#" << std::to_string(id_) << " " <<
|
||||||
|
what << ": " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
fail(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
std::cerr <<
|
||||||
|
what << ": " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
maybe_throw(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
fail(ec, what);
|
||||||
|
throw ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_accept(error_code ec)
|
||||||
|
{
|
||||||
|
if(! acceptor_.is_open())
|
||||||
|
return;
|
||||||
|
maybe_throw(ec, "accept");
|
||||||
|
socket_type sock(std::move(sock_));
|
||||||
|
acceptor_.async_accept(sock_,
|
||||||
|
std::bind(&http_async_server::on_accept, this,
|
||||||
|
asio::placeholders::error));
|
||||||
|
std::make_shared<peer>(std::move(sock), root_)->run();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
67
src/beast/examples/http_crawl.cpp
Normal file
67
src/beast/examples/http_crawl.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include "http_stream.h"
|
||||||
|
#include "urls_large_data.h"
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace beast::http;
|
||||||
|
using namespace boost::asio;
|
||||||
|
|
||||||
|
template<class String>
|
||||||
|
void
|
||||||
|
err(error_code const& ec, String const& what)
|
||||||
|
{
|
||||||
|
std::cerr << what << ": " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char const*[])
|
||||||
|
{
|
||||||
|
io_service ios;
|
||||||
|
for(auto const& host : urls_large_data())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ip::tcp::resolver r(ios);
|
||||||
|
auto it = r.resolve(
|
||||||
|
ip::tcp::resolver::query{host, "http"});
|
||||||
|
stream<ip::tcp::socket> hs(ios);
|
||||||
|
connect(hs.lowest_layer(), it);
|
||||||
|
auto ep = hs.lowest_layer().remote_endpoint();
|
||||||
|
request<empty_body> req({method_t::http_get, "/", 11});
|
||||||
|
req.headers.insert("Host", host +
|
||||||
|
std::string(":") + std::to_string(ep.port()));
|
||||||
|
req.headers.insert("User-Agent", "beast/http");
|
||||||
|
hs.write(req);
|
||||||
|
response<string_body> resp;
|
||||||
|
hs.read(resp);
|
||||||
|
std::cout << resp;
|
||||||
|
}
|
||||||
|
catch(boost::system::system_error const& ec)
|
||||||
|
{
|
||||||
|
std::cerr << host << ": " << ec.what();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
std::cerr << host << ": unknown exception" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
81
src/beast/examples/http_server.cpp
Normal file
81
src/beast/examples/http_server.cpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include "http_async_server.h"
|
||||||
|
#include "http_sync_server.h"
|
||||||
|
#include "sig_wait.h"
|
||||||
|
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(int ac, char const* av[])
|
||||||
|
{
|
||||||
|
using namespace beast::http;
|
||||||
|
namespace po = boost::program_options;
|
||||||
|
po::options_description desc("Options");
|
||||||
|
|
||||||
|
desc.add_options()
|
||||||
|
("root,r", po::value<std::string>()->implicit_value("."),
|
||||||
|
"Set the root directory for serving files")
|
||||||
|
("port,p", po::value<std::uint16_t>()->implicit_value(8080),
|
||||||
|
"Set the port number for the server")
|
||||||
|
("ip", po::value<std::string>()->implicit_value("0.0.0.0"),
|
||||||
|
"Set the IP address to bind to, \"0.0.0.0\" for all")
|
||||||
|
("threads,n", po::value<std::size_t>()->implicit_value(4),
|
||||||
|
"Set the number of threads to use")
|
||||||
|
("sync,s", "Launch a synchronous server")
|
||||||
|
;
|
||||||
|
po::variables_map vm;
|
||||||
|
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||||
|
|
||||||
|
std::string root = ".";
|
||||||
|
if(vm.count("root"))
|
||||||
|
root = vm["root"].as<std::string>();
|
||||||
|
|
||||||
|
std::uint16_t port = 8080;
|
||||||
|
if(vm.count("port"))
|
||||||
|
port = vm["port"].as<std::uint16_t>();
|
||||||
|
|
||||||
|
std::string ip = "0.0.0.0";
|
||||||
|
if(vm.count("ip"))
|
||||||
|
ip = vm["ip"].as<std::string>();
|
||||||
|
|
||||||
|
std::size_t threads = 4;
|
||||||
|
if(vm.count("threads"))
|
||||||
|
threads = vm["threads"].as<std::size_t>();
|
||||||
|
|
||||||
|
bool sync = vm.count("sync") > 0;
|
||||||
|
|
||||||
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
|
using address_type = boost::asio::ip::address;
|
||||||
|
|
||||||
|
endpoint_type ep{address_type::from_string(ip), port};
|
||||||
|
|
||||||
|
if(sync)
|
||||||
|
{
|
||||||
|
http_sync_server server(ep, root);
|
||||||
|
sig_wait();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
http_async_server server(ep, threads, root);
|
||||||
|
sig_wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/beast/examples/http_server_response.h
Normal file
31
src/beast/examples/http_server_response.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_EXAMPLE_SERVER_RESPONSE_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_EXAMPLE_SERVER_RESPONSE_H_INCLUDED
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
namespace example {
|
||||||
|
|
||||||
|
} // example
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
488
src/beast/examples/http_stream.h
Normal file
488
src/beast/examples/http_stream.h
Normal file
@@ -0,0 +1,488 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_STREAM_H_INCLUDED
|
||||||
|
#define BEAST_HTTP_STREAM_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/http.h>
|
||||||
|
#include <beast/asio/basic_streambuf.h>
|
||||||
|
#include <boost/asio/io_service.hpp>
|
||||||
|
#include <boost/intrusive/list.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class stream_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
struct op
|
||||||
|
: boost::intrusive::list_base_hook<
|
||||||
|
boost::intrusive::link_mode<
|
||||||
|
boost::intrusive::normal_link>>
|
||||||
|
{
|
||||||
|
virtual ~op() = default;
|
||||||
|
virtual void operator()() = 0;
|
||||||
|
virtual void cancel() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
using op_list = typename boost::intrusive::make_list<
|
||||||
|
op, boost::intrusive::constant_time_size<false>>::type;
|
||||||
|
|
||||||
|
op_list wr_q_;
|
||||||
|
bool wr_active_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
/** Provides message-oriented functionality using HTTP.
|
||||||
|
|
||||||
|
The stream class template provides asynchronous and blocking
|
||||||
|
message-oriented functionality necessary for clients and servers
|
||||||
|
to utilize the HTTP protocol.
|
||||||
|
|
||||||
|
@par Thread Safety
|
||||||
|
@e Distinct @e objects: Safe.@n
|
||||||
|
@e Shared @e objects: Unsafe. The application must ensure that
|
||||||
|
all asynchronous operations are performed within the same
|
||||||
|
implicit or explicit strand.
|
||||||
|
|
||||||
|
@par Example
|
||||||
|
|
||||||
|
To use the class template with an `ip::tcp::socket`, you would write:
|
||||||
|
|
||||||
|
@code
|
||||||
|
http::stream<ip::tcp::socket> hs(io_service);
|
||||||
|
@endcode
|
||||||
|
Alternatively, you can write:
|
||||||
|
@code
|
||||||
|
ip::tcp::socket sock(io_service);
|
||||||
|
http::stream<ip::tcp::socket&> hs(sock);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@note A stream object must not be destroyed while there are
|
||||||
|
pending asynchronous operations associated with it.
|
||||||
|
|
||||||
|
@par Concepts
|
||||||
|
AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
|
||||||
|
*/
|
||||||
|
template<class NextLayer,
|
||||||
|
class Allocator = std::allocator<char>>
|
||||||
|
class stream : public detail::stream_base
|
||||||
|
{
|
||||||
|
NextLayer next_layer_;
|
||||||
|
basic_streambuf<Allocator> rd_buf_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type of the next layer.
|
||||||
|
using next_layer_type =
|
||||||
|
std::remove_reference_t<NextLayer>;
|
||||||
|
|
||||||
|
/// The type of the lowest layer.
|
||||||
|
using lowest_layer_type =
|
||||||
|
typename next_layer_type::lowest_layer_type;
|
||||||
|
|
||||||
|
/// The type of endpoint of the lowest layer.
|
||||||
|
using endpoint_type =
|
||||||
|
typename lowest_layer_type::endpoint_type;
|
||||||
|
|
||||||
|
/// The protocol of the next layer.
|
||||||
|
using protocol_type =
|
||||||
|
typename lowest_layer_type::protocol_type;
|
||||||
|
|
||||||
|
/// The type of resolver of the next layer.
|
||||||
|
using resolver_type =
|
||||||
|
typename protocol_type::resolver;
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
|
||||||
|
@note A stream object must not be destroyed while there
|
||||||
|
are pending asynchronous operations associated with it.
|
||||||
|
*/
|
||||||
|
~stream();
|
||||||
|
|
||||||
|
/** Move constructor.
|
||||||
|
|
||||||
|
Undefined behavior if operations are active or pending.
|
||||||
|
*/
|
||||||
|
stream(stream&&) = default;
|
||||||
|
|
||||||
|
/** Move assignment.
|
||||||
|
|
||||||
|
Undefined behavior if operations are active or pending.
|
||||||
|
*/
|
||||||
|
stream& operator=(stream&&) = default;
|
||||||
|
|
||||||
|
/** Construct a HTTP stream.
|
||||||
|
|
||||||
|
This constructor creates a HTTP stream and initialises
|
||||||
|
the next layer.
|
||||||
|
|
||||||
|
@throws Any exceptions thrown by the Stream constructor.
|
||||||
|
|
||||||
|
@param args The arguments to be passed to initialise the
|
||||||
|
next layer. The arguments are forwarded to the next layer's
|
||||||
|
constructor.
|
||||||
|
*/
|
||||||
|
template<class... Args>
|
||||||
|
explicit
|
||||||
|
stream(Args&&... args);
|
||||||
|
|
||||||
|
/** Get the io_service associated with the stream.
|
||||||
|
|
||||||
|
This function may be used to obtain the io_service object
|
||||||
|
that the stream uses to dispatch handlers for asynchronous
|
||||||
|
operations.
|
||||||
|
|
||||||
|
@return A reference to the io_service object that the stream
|
||||||
|
will use to dispatch handlers. Ownership is not transferred
|
||||||
|
to the caller.
|
||||||
|
*/
|
||||||
|
boost::asio::io_service&
|
||||||
|
get_io_service()
|
||||||
|
{
|
||||||
|
return next_layer_.lowest_layer().get_io_service();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a reference to the next layer.
|
||||||
|
|
||||||
|
This function returns a reference to the next layer
|
||||||
|
in a stack of stream layers.
|
||||||
|
|
||||||
|
@return A reference to the next layer in the stack of
|
||||||
|
stream layers. Ownership is not transferred to the caller.
|
||||||
|
*/
|
||||||
|
next_layer_type&
|
||||||
|
next_layer()
|
||||||
|
{
|
||||||
|
return next_layer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a reference to the next layer.
|
||||||
|
|
||||||
|
This function returns a reference to the next layer in a
|
||||||
|
stack of stream layers.
|
||||||
|
|
||||||
|
@return A reference to the next layer in the stack of
|
||||||
|
stream layers. Ownership is not transferred to the caller.
|
||||||
|
*/
|
||||||
|
next_layer_type const&
|
||||||
|
next_layer() const
|
||||||
|
{
|
||||||
|
return next_layer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a reference to the lowest layer.
|
||||||
|
|
||||||
|
This function returns a reference to the lowest layer
|
||||||
|
in a stack of stream layers.
|
||||||
|
|
||||||
|
@return A reference to the lowest layer in the stack of
|
||||||
|
stream layers. Ownership is not transferred to the caller.
|
||||||
|
*/
|
||||||
|
lowest_layer_type&
|
||||||
|
lowest_layer()
|
||||||
|
{
|
||||||
|
return next_layer_.lowest_layer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a reference to the lowest layer.
|
||||||
|
|
||||||
|
This function returns a reference to the lowest layer
|
||||||
|
in a stack of stream layers.
|
||||||
|
|
||||||
|
@return A reference to the lowest layer in the stack of
|
||||||
|
stream layers. Ownership is not transferred to the caller.
|
||||||
|
*/
|
||||||
|
lowest_layer_type const&
|
||||||
|
lowest_layer() const
|
||||||
|
{
|
||||||
|
return next_layer_.lowest_layer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cancel pending operations.
|
||||||
|
|
||||||
|
This will cancel all of the asynchronous operations pending,
|
||||||
|
including pipelined writes that have not been started. Handlers for
|
||||||
|
canceled writes will be called with
|
||||||
|
`boost::asio::error::operation_aborted`.
|
||||||
|
|
||||||
|
@throws boost::system::system_error Thrown on failure.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cancel()
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
cancel(ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cancel pending operations.
|
||||||
|
|
||||||
|
This will cancel all of the asynchronous operations pending,
|
||||||
|
including pipelined writes that have not been started. Handlers for
|
||||||
|
canceled writes will be called with
|
||||||
|
`boost::asio::error::operation_aborted`.
|
||||||
|
|
||||||
|
@param ec Set to indicate what error occurred, if any.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cancel(error_code& ec);
|
||||||
|
|
||||||
|
/** Read a HTTP message from the stream.
|
||||||
|
|
||||||
|
This function is used to read a single HTTP message from the stream.
|
||||||
|
The call will block until one of the followign conditions is true:
|
||||||
|
|
||||||
|
@li A message has been read.
|
||||||
|
|
||||||
|
@li An error occurred.
|
||||||
|
|
||||||
|
The operation is implemented in terms of zero or more calls to the
|
||||||
|
next layer's `read_some` function.
|
||||||
|
|
||||||
|
@param msg An object used to store the message. The previous
|
||||||
|
contents of the object will be overwritten.
|
||||||
|
|
||||||
|
@throws boost::system::system_error Thrown on failure.
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
read(message<isRequest, Body, Headers>& msg)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
read(msg, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read a HTTP message from the stream.
|
||||||
|
|
||||||
|
This function is used to read a single HTTP message from the stream.
|
||||||
|
The call will block until one of the followign conditions is true:
|
||||||
|
|
||||||
|
@li A message has been read.
|
||||||
|
|
||||||
|
@li An error occurred.
|
||||||
|
|
||||||
|
The operation is implemented in terms of zero or more calls to the
|
||||||
|
next layer's `read_some` function.
|
||||||
|
|
||||||
|
@param msg An object used to store the message. The previous
|
||||||
|
contents of the object will be overwritten.
|
||||||
|
|
||||||
|
@param ec Set to indicate what error occurred, if any.
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
read(message<isRequest, Body, Headers>& msg,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
|
/** Start reading a HTTP message from the stream asynchronously.
|
||||||
|
|
||||||
|
This function is used to asynchronously read a single HTTP message
|
||||||
|
from the stream. The function call always returns immediately. The
|
||||||
|
asynchronous operation will continue until one of the following
|
||||||
|
conditions is true:
|
||||||
|
|
||||||
|
@li The message has been written.
|
||||||
|
|
||||||
|
@li An error occurred.
|
||||||
|
|
||||||
|
This operation is implemented in terms of zero or more calls to the
|
||||||
|
next layer's async_read_some function, and is known as a composed
|
||||||
|
operation. The program must ensure that the stream performs no other
|
||||||
|
read operations or any other composed operations that perform reads
|
||||||
|
until this operation completes.
|
||||||
|
|
||||||
|
@param msg An object used to store the message. The previous
|
||||||
|
contents of the object will be overwritten. Ownership of the message
|
||||||
|
is not transferred; the caller must guarantee that the object remains
|
||||||
|
valid until the handler is called.
|
||||||
|
|
||||||
|
@param handler The handler to be called when the request completes.
|
||||||
|
Copies will be made of the handler as required. The equivalent
|
||||||
|
function signature of the handler must be:
|
||||||
|
@code void handler(
|
||||||
|
error_code const& error // result of operation
|
||||||
|
); @endcode
|
||||||
|
Regardless of whether the asynchronous operation completes
|
||||||
|
immediately or not, the handler will not be invoked from within
|
||||||
|
this function. Invocation of the handler will be performed in a
|
||||||
|
manner equivalent to using boost::asio::io_service::post().
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers,
|
||||||
|
class ReadHandler>
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
void_or_deduced
|
||||||
|
#else
|
||||||
|
auto
|
||||||
|
#endif
|
||||||
|
async_read(message<isRequest, Body, Headers>& msg,
|
||||||
|
ReadHandler&& handler);
|
||||||
|
|
||||||
|
/** Write a HTTP message to the stream.
|
||||||
|
|
||||||
|
This function is used to write a single HTTP message to the
|
||||||
|
stream. The call will block until one of the following conditions
|
||||||
|
is true:
|
||||||
|
|
||||||
|
@li The entire message is sent.
|
||||||
|
|
||||||
|
@li An error occurred.
|
||||||
|
|
||||||
|
If the semantics of the message require that the connection is
|
||||||
|
closed to indicate the end of the content body,
|
||||||
|
`boost::asio::error::eof` is thrown after the message is sent.
|
||||||
|
successfuly. The caller is responsible for actually closing the
|
||||||
|
connection. For regular TCP/IP streams this means shutting down the
|
||||||
|
send side, while SSL streams may call the SSL shutdown function.
|
||||||
|
|
||||||
|
@param msg The message to send.
|
||||||
|
|
||||||
|
@throws boost::system::system_error Thrown on failure.
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
write(message<isRequest, Body, Headers> const& msg)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
write(msg, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write a HTTP message to the stream.
|
||||||
|
|
||||||
|
This function is used to write a single HTTP message to the
|
||||||
|
stream. The call will block until one of the following conditions
|
||||||
|
is true:
|
||||||
|
|
||||||
|
@li The entire message is sent.
|
||||||
|
|
||||||
|
@li An error occurred.
|
||||||
|
|
||||||
|
If the semantics of the message require that the connection is
|
||||||
|
closed to indicate the end of the content body,
|
||||||
|
`boost::asio::error::eof` is returned after the message is sent.
|
||||||
|
successfuly. The caller is responsible for actually closing the
|
||||||
|
connection. For regular TCP/IP streams this means shutting down the
|
||||||
|
send side, while SSL streams may call the SSL shutdown function.
|
||||||
|
|
||||||
|
@param msg The message to send.
|
||||||
|
|
||||||
|
@param ec Set to the error, if any occurred.
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
write(message<isRequest, Body, Headers> const& msg,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
|
/** Start pipelining a HTTP message to the stream asynchronously.
|
||||||
|
|
||||||
|
This function is used to queue a message to be sent on the stream.
|
||||||
|
Unlike the free function, this version will place the message on an
|
||||||
|
outgoing message queue if there is already a write pending.
|
||||||
|
|
||||||
|
If the semantics of the message require that the connection is
|
||||||
|
closed to indicate the end of the content body, the handler
|
||||||
|
is called with the error `boost::asio::error::eof` after the message
|
||||||
|
has been sent successfully. The caller is responsible for actually
|
||||||
|
closing the connection. For regular TCP/IP streams this means
|
||||||
|
shutting down the send side, while SSL streams may call the SSL
|
||||||
|
`async_shutdown` function.
|
||||||
|
|
||||||
|
@param msg The message to send. A copy of the message will be made.
|
||||||
|
|
||||||
|
@param handler The handler to be called when the request completes.
|
||||||
|
Copies will be made of the handler as required. The equivalent
|
||||||
|
function signature of the handler must be:
|
||||||
|
@code void handler(
|
||||||
|
error_code const& error // result of operation
|
||||||
|
); @endcode
|
||||||
|
Regardless of whether the asynchronous operation completes
|
||||||
|
immediately or not, the handler will not be invoked from within
|
||||||
|
this function. Invocation of the handler will be performed in a
|
||||||
|
manner equivalent to using boost::asio::io_service::post().
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers,
|
||||||
|
class WriteHandler>
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
void_or_deduced
|
||||||
|
#else
|
||||||
|
auto
|
||||||
|
#endif
|
||||||
|
async_write(message<isRequest, Body, Headers> const& msg,
|
||||||
|
WriteHandler&& handler);
|
||||||
|
|
||||||
|
/** Start pipelining a HTTP message to the stream asynchronously.
|
||||||
|
|
||||||
|
This function is used to queue a message to be sent on the stream.
|
||||||
|
Unlike the free function, this version will place the message on an
|
||||||
|
outgoing message queue if there is already a write pending.
|
||||||
|
|
||||||
|
If the semantics of the message require that the connection is
|
||||||
|
closed to indicate the end of the content body, the handler
|
||||||
|
is called with the error boost::asio::error::eof. The caller is
|
||||||
|
responsible for actually closing the connection. For regular
|
||||||
|
TCP/IP streams this means shutting down the send side, while SSL
|
||||||
|
streams may call the SSL async_shutdown function.
|
||||||
|
|
||||||
|
@param msg The message to send. Ownership of the message, which
|
||||||
|
must be movable, is transferred to the implementation. The message
|
||||||
|
will not be destroyed until the asynchronous operation completes.
|
||||||
|
|
||||||
|
@param handler The handler to be called when the request completes.
|
||||||
|
Copies will be made of the handler as required. The equivalent
|
||||||
|
function signature of the handler must be:
|
||||||
|
@code void handler(
|
||||||
|
error_code const& error // result of operation
|
||||||
|
); @endcode
|
||||||
|
Regardless of whether the asynchronous operation completes
|
||||||
|
immediately or not, the handler will not be invoked from within
|
||||||
|
this function. Invocation of the handler will be performed in a
|
||||||
|
manner equivalent to using boost::asio::io_service::post().
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Body, class Headers,
|
||||||
|
class WriteHandler>
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
void_or_deduced
|
||||||
|
#else
|
||||||
|
auto
|
||||||
|
#endif
|
||||||
|
async_write(message<isRequest, Body, Headers>&& msg,
|
||||||
|
WriteHandler&& handler);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<bool, class, class, class> class read_op;
|
||||||
|
template<bool, class, class, class> class write_op;
|
||||||
|
|
||||||
|
void
|
||||||
|
cancel_all();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include "http_stream.ipp"
|
||||||
|
|
||||||
|
#endif
|
||||||
419
src/beast/examples/http_stream.ipp
Normal file
419
src/beast/examples/http_stream.ipp
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_STREAM_IPP_INCLUDED
|
||||||
|
#define BEAST_HTTP_STREAM_IPP_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/asio/async_completion.h>
|
||||||
|
#include <beast/asio/bind_handler.h>
|
||||||
|
#include <beast/asio/handler_alloc.h>
|
||||||
|
#include <beast/http/read.h>
|
||||||
|
#include <beast/http/type_check.h>
|
||||||
|
#include <beast/http/write.h>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers,
|
||||||
|
class Handler>
|
||||||
|
class stream<NextLayer, Allocator>::read_op
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
handler_alloc<char, Handler>;
|
||||||
|
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
stream<NextLayer>& s;
|
||||||
|
message<isRequest, Body, Headers>& m;
|
||||||
|
Handler h;
|
||||||
|
bool cont;
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
||||||
|
message<isRequest, Body, Headers>& m_)
|
||||||
|
: s(s_)
|
||||||
|
, m(m_)
|
||||||
|
, h(std::forward<DeducedHandler>(h_))
|
||||||
|
, cont(boost_asio_handler_cont_helpers::
|
||||||
|
is_continuation(h))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<data> d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
read_op(read_op&&) = default;
|
||||||
|
read_op(read_op const&) = default;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
read_op(DeducedHandler&& h,
|
||||||
|
stream<NextLayer>& s, Args&&... args)
|
||||||
|
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||||
|
std::forward<DeducedHandler>(h), s,
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
(*this)(error_code{}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(error_code const& ec, bool again = true);
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_allocate(
|
||||||
|
std::size_t size, read_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
allocate(size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, read_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
deallocate(p, size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_is_continuation(read_op* op)
|
||||||
|
{
|
||||||
|
return op->d_->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
friend
|
||||||
|
auto asio_handler_invoke(Function&& f, read_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::
|
||||||
|
invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers, class Handler>
|
||||||
|
void
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
read_op<isRequest, Body, Headers, Handler>::
|
||||||
|
operator()(error_code const& ec, bool again)
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.cont = d.cont || again;
|
||||||
|
while(! ec && d.state != 99)
|
||||||
|
{
|
||||||
|
switch(d.state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
d.state = 99;
|
||||||
|
beast::http::async_read(d.s.next_layer_,
|
||||||
|
d.s.rd_buf_, d.m, std::move(*this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.h(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers,
|
||||||
|
class Handler>
|
||||||
|
class stream<NextLayer, Allocator>::write_op : public op
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
handler_alloc<char, Handler>;
|
||||||
|
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
stream<NextLayer>& s;
|
||||||
|
message<isRequest, Body, Headers> m;
|
||||||
|
Handler h;
|
||||||
|
bool cont;
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
||||||
|
message<isRequest, Body, Headers> const& m_,
|
||||||
|
bool cont_)
|
||||||
|
: s(s_)
|
||||||
|
, m(m_)
|
||||||
|
, h(std::forward<DeducedHandler>(h_))
|
||||||
|
, cont(cont_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
||||||
|
message<isRequest, Body, Headers>&& m_,
|
||||||
|
bool cont_)
|
||||||
|
: s(s_)
|
||||||
|
, m(std::move(m_))
|
||||||
|
, h(std::forward<DeducedHandler>(h_))
|
||||||
|
, cont(cont_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<data> d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
write_op(write_op&&) = default;
|
||||||
|
write_op(write_op const&) = default;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
write_op(DeducedHandler&& h,
|
||||||
|
stream<NextLayer>& s, Args&&... args)
|
||||||
|
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||||
|
std::forward<DeducedHandler>(h), s,
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()() override
|
||||||
|
{
|
||||||
|
(*this)(error_code{}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel() override;
|
||||||
|
|
||||||
|
void operator()(error_code const& ec, bool again = true);
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_allocate(
|
||||||
|
std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
allocate(size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
deallocate(p, size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_is_continuation(write_op* op)
|
||||||
|
{
|
||||||
|
return op->d_->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
friend
|
||||||
|
auto asio_handler_invoke(Function&& f, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::
|
||||||
|
invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers, class Handler>
|
||||||
|
void
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
write_op<isRequest, Body, Headers, Handler>::
|
||||||
|
cancel()
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.s.get_io_service().post(
|
||||||
|
bind_handler(std::move(*this),
|
||||||
|
boost::asio::error::operation_aborted));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers, class Handler>
|
||||||
|
void
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
write_op<isRequest, Body, Headers, Handler>::
|
||||||
|
operator()(error_code const& ec, bool again)
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.cont = d.cont || again;
|
||||||
|
while(! ec && d.state != 99)
|
||||||
|
{
|
||||||
|
switch(d.state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
d.state = 99;
|
||||||
|
beast::http::async_write(d.s.next_layer_,
|
||||||
|
d.m, std::move(*this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.h(ec);
|
||||||
|
if(! d.s.wr_q_.empty())
|
||||||
|
{
|
||||||
|
auto& op = d.s.wr_q_.front();
|
||||||
|
op();
|
||||||
|
// VFALCO Use allocator
|
||||||
|
delete &op;
|
||||||
|
d.s.wr_q_.pop_front();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d.s.wr_active_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
~stream()
|
||||||
|
{
|
||||||
|
// Can't destroy with pending operations!
|
||||||
|
assert(wr_q_.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<class... Args>
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
stream(Args&&... args)
|
||||||
|
: next_layer_(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
void
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
cancel(error_code& ec)
|
||||||
|
{
|
||||||
|
cancel_all();
|
||||||
|
lowest_layer().cancel(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
read(message<isRequest, Body, Headers>& msg,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
beast::http::read(next_layer_, rd_buf_, msg, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers,
|
||||||
|
class ReadHandler>
|
||||||
|
auto
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
async_read(message<isRequest, Body, Headers>& msg,
|
||||||
|
ReadHandler&& handler)
|
||||||
|
{
|
||||||
|
async_completion<
|
||||||
|
ReadHandler, void(error_code)
|
||||||
|
> completion(handler);
|
||||||
|
read_op<isRequest, Body, Headers,
|
||||||
|
decltype(completion.handler)>{
|
||||||
|
completion.handler, *this, msg};
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
write(message<isRequest, Body, Headers> const& msg,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
beast::http::write(next_layer_, msg, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers,
|
||||||
|
class WriteHandler>
|
||||||
|
auto
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
async_write(message<isRequest, Body, Headers> const& msg,
|
||||||
|
WriteHandler&& handler)
|
||||||
|
{
|
||||||
|
async_completion<
|
||||||
|
WriteHandler, void(error_code)> completion(handler);
|
||||||
|
auto const cont = wr_active_ ||
|
||||||
|
boost_asio_handler_cont_helpers::is_continuation(handler);
|
||||||
|
if(! wr_active_)
|
||||||
|
{
|
||||||
|
wr_active_ = true;
|
||||||
|
write_op<isRequest, Body, Headers,
|
||||||
|
decltype(completion.handler)>{
|
||||||
|
completion.handler, *this, msg, cont }();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// VFALCO Use allocator
|
||||||
|
wr_q_.push_back(*new write_op<isRequest, Body, Headers,
|
||||||
|
decltype(completion.handler)>(
|
||||||
|
completion.handler, *this, msg, cont));
|
||||||
|
}
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
template<bool isRequest, class Body, class Headers,
|
||||||
|
class WriteHandler>
|
||||||
|
auto
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
async_write(message<isRequest, Body, Headers>&& msg,
|
||||||
|
WriteHandler&& handler)
|
||||||
|
{
|
||||||
|
async_completion<
|
||||||
|
WriteHandler, void(error_code)> completion(handler);
|
||||||
|
auto const cont = wr_active_ ||
|
||||||
|
boost_asio_handler_cont_helpers::is_continuation(handler);
|
||||||
|
if(! wr_active_)
|
||||||
|
{
|
||||||
|
wr_active_ = true;
|
||||||
|
write_op<isRequest, Body, Headers,
|
||||||
|
decltype(completion.handler)>{completion.handler,
|
||||||
|
*this, std::move(msg), cont}();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// VFALCO Use allocator
|
||||||
|
wr_q_.push_back(*new write_op<isRequest, Body, Headers,
|
||||||
|
decltype(completion.handler)>(completion.handler,
|
||||||
|
*this, std::move(msg), cont));
|
||||||
|
}
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, class Allocator>
|
||||||
|
void
|
||||||
|
stream<NextLayer, Allocator>::
|
||||||
|
cancel_all()
|
||||||
|
{
|
||||||
|
for(auto it = wr_q_.begin(); it != wr_q_.end();)
|
||||||
|
{
|
||||||
|
auto& op = *it++;
|
||||||
|
op.cancel();
|
||||||
|
// VFALCO Use allocator
|
||||||
|
delete &op;
|
||||||
|
}
|
||||||
|
wr_q_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
170
src/beast/examples/http_sync_server.h
Normal file
170
src/beast/examples/http_sync_server.h
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
||||||
|
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
||||||
|
|
||||||
|
#include "file_body.h"
|
||||||
|
#include "http_stream.h"
|
||||||
|
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
class http_sync_server
|
||||||
|
{
|
||||||
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
|
using address_type = boost::asio::ip::address;
|
||||||
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
|
using req_type = request<string_body>;
|
||||||
|
using resp_type = response<file_body>;
|
||||||
|
|
||||||
|
boost::asio::io_service ios_;
|
||||||
|
socket_type sock_;
|
||||||
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
|
std::string root_;
|
||||||
|
std::thread thread_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
http_sync_server(endpoint_type const& ep,
|
||||||
|
std::string const& root)
|
||||||
|
: sock_(ios_)
|
||||||
|
, acceptor_(ios_)
|
||||||
|
, root_(root)
|
||||||
|
{
|
||||||
|
acceptor_.open(ep.protocol());
|
||||||
|
acceptor_.bind(ep);
|
||||||
|
acceptor_.listen(
|
||||||
|
boost::asio::socket_base::max_connections);
|
||||||
|
acceptor_.async_accept(sock_,
|
||||||
|
std::bind(&http_sync_server::on_accept, this,
|
||||||
|
beast::asio::placeholders::error));
|
||||||
|
thread_ = std::thread{[&]{ ios_.run(); }};
|
||||||
|
}
|
||||||
|
|
||||||
|
~http_sync_server()
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ios_.dispatch(
|
||||||
|
[&]{ acceptor_.close(ec); });
|
||||||
|
thread_.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fail(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
std::cerr <<
|
||||||
|
what << ": " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
maybe_throw(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
fail(ec, what);
|
||||||
|
throw ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_accept(error_code ec)
|
||||||
|
{
|
||||||
|
if(! acceptor_.is_open())
|
||||||
|
return;
|
||||||
|
maybe_throw(ec, "accept");
|
||||||
|
static int id_ = 0;
|
||||||
|
std::thread{
|
||||||
|
[
|
||||||
|
id = ++id_,
|
||||||
|
this,
|
||||||
|
sock = std::move(sock_),
|
||||||
|
work = boost::asio::io_service::work{ios_}
|
||||||
|
]() mutable
|
||||||
|
{
|
||||||
|
do_peer(id, std::move(sock));
|
||||||
|
}}.detach();
|
||||||
|
acceptor_.async_accept(sock_,
|
||||||
|
std::bind(&http_sync_server::on_accept, this,
|
||||||
|
asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fail(int id, error_code const& ec)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted &&
|
||||||
|
ec != boost::asio::error::eof)
|
||||||
|
std::cerr <<
|
||||||
|
"#" << std::to_string(id) << " " << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
do_peer(int id, socket_type&& sock)
|
||||||
|
{
|
||||||
|
http::stream<socket_type> hs(std::move(sock));
|
||||||
|
error_code ec;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
req_type req;
|
||||||
|
hs.read(req, ec);
|
||||||
|
if(ec)
|
||||||
|
break;
|
||||||
|
auto path = req.url;
|
||||||
|
if(path == "/")
|
||||||
|
path = "/index.html";
|
||||||
|
path = root_ + path;
|
||||||
|
if(! boost::filesystem::exists(path))
|
||||||
|
{
|
||||||
|
response<string_body> resp(
|
||||||
|
{404, "Not Found", req.version});
|
||||||
|
resp.headers.replace("Server", "http_sync_server");
|
||||||
|
resp.body = "The file '" + path + "' was not found";
|
||||||
|
hs.write(resp, ec);
|
||||||
|
if(ec)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
response<file_body> resp(
|
||||||
|
{200, "OK", req.version});
|
||||||
|
resp.headers.replace("Server", "http_sync_server");
|
||||||
|
resp.headers.replace("Content-Type", "text/html");
|
||||||
|
resp.body = path;
|
||||||
|
hs.write(resp, ec);
|
||||||
|
if(ec)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fail(id, ec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
49
src/beast/examples/sig_wait.h
Normal file
49
src/beast/examples/sig_wait.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_SIG_WAIT_H_INCLUDED
|
||||||
|
#define BEAST_EXAMPLE_SIG_WAIT_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
// Block until SIGINT or SIGTERM
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
sig_wait()
|
||||||
|
{
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::signal_set signals(
|
||||||
|
ios, SIGINT, SIGTERM);
|
||||||
|
std::mutex m;
|
||||||
|
bool stop = false;
|
||||||
|
std::condition_variable cv;
|
||||||
|
signals.async_wait(
|
||||||
|
[&](boost::system::error_code const&, int)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m);
|
||||||
|
stop = true;
|
||||||
|
cv.notify_one();
|
||||||
|
});
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
cv.wait(lock, [&]{ return stop; });
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -17,15 +17,12 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/http/tests/urls_large_data.h>
|
#include "urls_large_data.h"
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
|
|
||||||
// Data from Alexa top 1 million sites
|
// Data from Alexa top 1 million sites
|
||||||
// http://s3.amazonaws.com/alexa-static/top-1m.csv.zip
|
// http://s3.amazonaws.com/alexa-static/top-1m.csv.zip
|
||||||
//
|
//
|
||||||
std::vector <char const*> const&
|
std::vector<char const*> const&
|
||||||
urls_large_data()
|
urls_large_data()
|
||||||
{
|
{
|
||||||
static std::vector <char const*> const urls ({
|
static std::vector <char const*> const urls ({
|
||||||
@@ -10032,7 +10029,3 @@ urls_large_data()
|
|||||||
|
|
||||||
return urls;
|
return urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -17,18 +17,12 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_URLS_LARGE_DATA_H_INCLUDED
|
#ifndef URLS_LARGE_DATA_H_INCLUDED
|
||||||
#define BEAST_HTTP_URLS_LARGE_DATA_H_INCLUDED
|
#define URLS_LARGE_DATA_H_INCLUDED
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace beast {
|
std::vector<char const*> const&
|
||||||
namespace http {
|
|
||||||
|
|
||||||
std::vector <char const*> const&
|
|
||||||
urls_large_data();
|
urls_large_data();
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -14,6 +14,7 @@ unit-test all :
|
|||||||
asio.cpp
|
asio.cpp
|
||||||
async_completion.cpp
|
async_completion.cpp
|
||||||
basic_streambuf.cpp
|
basic_streambuf.cpp
|
||||||
|
../basic_headers.cpp
|
||||||
bind_handler.cpp
|
bind_handler.cpp
|
||||||
buffers_adapter.cpp
|
buffers_adapter.cpp
|
||||||
buffers_debug.cpp
|
buffers_debug.cpp
|
||||||
|
|||||||
63
src/beast/test/basic_headers.cpp
Normal file
63
src/beast/test/basic_headers.cpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
//
|
||||||
|
// 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_headers.h>
|
||||||
|
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class basic_headers_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class Allocator>
|
||||||
|
using bha = basic_headers<Allocator>;
|
||||||
|
|
||||||
|
using bh = basic_headers<std::allocator<char>>;
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
static
|
||||||
|
void
|
||||||
|
fill(std::size_t n, basic_headers<Allocator>& h)
|
||||||
|
{
|
||||||
|
for(std::size_t i = 1; i<= n; ++i)
|
||||||
|
h.insert(std::to_string(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testHeaders()
|
||||||
|
{
|
||||||
|
bh h1;
|
||||||
|
expect(h1.empty());
|
||||||
|
fill(1, h1);
|
||||||
|
expect(h1.size() == 1);
|
||||||
|
bh h2;
|
||||||
|
h2 = h1;
|
||||||
|
expect(h2.size() == 1);
|
||||||
|
h2.insert("2", "2");
|
||||||
|
expect(std::distance(h2.begin(), h2.end()) == 2);
|
||||||
|
h1 = std::move(h2);
|
||||||
|
expect(h1.size() == 2);
|
||||||
|
expect(h2.size() == 0);
|
||||||
|
bh h3(std::move(h1));
|
||||||
|
expect(h3.size() == 2);
|
||||||
|
expect(h1.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testHeaders();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(basic_headers,http,beast);
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // asio
|
||||||
|
} // beast
|
||||||
@@ -17,7 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/http/URL.h>
|
#include <ripple/beast/net/URL.h>
|
||||||
|
#include <beast/http/src/nodejs_parser.h>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
@@ -104,9 +105,9 @@ parse_URL(std::string const& url)
|
|||||||
std::size_t const buflen (url.size ());
|
std::size_t const buflen (url.size ());
|
||||||
char const* const buf (url.c_str ());
|
char const* const buf (url.c_str ());
|
||||||
|
|
||||||
joyent::http_parser_url parser;
|
http_parser_url parser;
|
||||||
|
|
||||||
if (joyent::http_parser_parse_url (buf, buflen, false, &parser) != 0)
|
if (http_parser_parse_url (buf, buflen, false, &parser) != 0)
|
||||||
return std::make_pair (false, URL{});
|
return std::make_pair (false, URL{});
|
||||||
|
|
||||||
std::string scheme;
|
std::string scheme;
|
||||||
@@ -118,54 +119,54 @@ parse_URL(std::string const& url)
|
|||||||
std::string fragment;
|
std::string fragment;
|
||||||
std::string userinfo;
|
std::string userinfo;
|
||||||
|
|
||||||
if ((parser.field_set & (1<<joyent::UF_SCHEMA)) != 0)
|
if ((parser.field_set & (1<<UF_SCHEMA)) != 0)
|
||||||
{
|
{
|
||||||
scheme = std::string (
|
scheme = std::string (
|
||||||
buf + parser.field_data [joyent::UF_SCHEMA].off,
|
buf + parser.field_data [UF_SCHEMA].off,
|
||||||
parser.field_data [joyent::UF_SCHEMA].len);
|
parser.field_data [UF_SCHEMA].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((parser.field_set & (1<<joyent::UF_HOST)) != 0)
|
if ((parser.field_set & (1<<UF_HOST)) != 0)
|
||||||
{
|
{
|
||||||
host = std::string (
|
host = std::string (
|
||||||
buf + parser.field_data [joyent::UF_HOST].off,
|
buf + parser.field_data [UF_HOST].off,
|
||||||
parser.field_data [joyent::UF_HOST].len);
|
parser.field_data [UF_HOST].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((parser.field_set & (1<<joyent::UF_PORT)) != 0)
|
if ((parser.field_set & (1<<UF_PORT)) != 0)
|
||||||
{
|
{
|
||||||
port = parser.port;
|
port = parser.port;
|
||||||
port_string = std::string (
|
port_string = std::string (
|
||||||
buf + parser.field_data [joyent::UF_PORT].off,
|
buf + parser.field_data [UF_PORT].off,
|
||||||
parser.field_data [joyent::UF_PORT].len);
|
parser.field_data [UF_PORT].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((parser.field_set & (1<<joyent::UF_PATH)) != 0)
|
if ((parser.field_set & (1<<UF_PATH)) != 0)
|
||||||
{
|
{
|
||||||
path = std::string (
|
path = std::string (
|
||||||
buf + parser.field_data [joyent::UF_PATH].off,
|
buf + parser.field_data [UF_PATH].off,
|
||||||
parser.field_data [joyent::UF_PATH].len);
|
parser.field_data [UF_PATH].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((parser.field_set & (1<<joyent::UF_QUERY)) != 0)
|
if ((parser.field_set & (1<<UF_QUERY)) != 0)
|
||||||
{
|
{
|
||||||
query = std::string (
|
query = std::string (
|
||||||
buf + parser.field_data [joyent::UF_QUERY].off,
|
buf + parser.field_data [UF_QUERY].off,
|
||||||
parser.field_data [joyent::UF_QUERY].len);
|
parser.field_data [UF_QUERY].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((parser.field_set & (1<<joyent::UF_FRAGMENT)) != 0)
|
if ((parser.field_set & (1<<UF_FRAGMENT)) != 0)
|
||||||
{
|
{
|
||||||
fragment = std::string (
|
fragment = std::string (
|
||||||
buf + parser.field_data [joyent::UF_FRAGMENT].off,
|
buf + parser.field_data [UF_FRAGMENT].off,
|
||||||
parser.field_data [joyent::UF_FRAGMENT].len);
|
parser.field_data [UF_FRAGMENT].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((parser.field_set & (1<<joyent::UF_USERINFO)) != 0)
|
if ((parser.field_set & (1<<UF_USERINFO)) != 0)
|
||||||
{
|
{
|
||||||
userinfo = std::string (
|
userinfo = std::string (
|
||||||
buf + parser.field_data [joyent::UF_USERINFO].off,
|
buf + parser.field_data [UF_USERINFO].off,
|
||||||
parser.field_data [joyent::UF_USERINFO].len);
|
parser.field_data [UF_USERINFO].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair (true,
|
return std::make_pair (true,
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/http/URL.h>
|
#include <ripple/beast/net/URL.h>
|
||||||
|
|
||||||
#include <beast/unit_test/suite.h>
|
#include <beast/unit_test/suite.h>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
@@ -21,4 +21,7 @@
|
|||||||
#include <ripple/beast/net/impl/IPAddressV6.cpp>
|
#include <ripple/beast/net/impl/IPAddressV6.cpp>
|
||||||
#include <ripple/beast/net/impl/IPEndpoint.cpp>
|
#include <ripple/beast/net/impl/IPEndpoint.cpp>
|
||||||
#include <ripple/beast/net/impl/IPAddressConversion.cpp>
|
#include <ripple/beast/net/impl/IPAddressConversion.cpp>
|
||||||
|
#include <ripple/beast/net/impl/URL.cpp>
|
||||||
|
|
||||||
|
#include <ripple/beast/net/tests/beast_http_URL_test.cpp>
|
||||||
#include <ripple/beast/net/tests/IPEndpoint.test.cpp>
|
#include <ripple/beast/net/tests/IPEndpoint.test.cpp>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include <ripple/protocol/PublicKey.h> // NIKB Breaks levelization (TEMP)
|
#include <ripple/protocol/PublicKey.h> // NIKB Breaks levelization (TEMP)
|
||||||
#include <ripple/protocol/SecretKey.h> // NIKB Breaks levelization (TEMP)
|
#include <ripple/protocol/SecretKey.h> // NIKB Breaks levelization (TEMP)
|
||||||
#include <ripple/json/json_value.h>
|
#include <ripple/json/json_value.h>
|
||||||
#include <beast/http/URL.h>
|
#include <ripple/beast/net/URL.h>
|
||||||
#include <ripple/beast/net/IPEndpoint.h>
|
#include <ripple/beast/net/IPEndpoint.h>
|
||||||
#include <beast/ci_char_traits.h>
|
#include <beast/ci_char_traits.h>
|
||||||
#include <ripple/beast/utility/Journal.h>
|
#include <ripple/beast/utility/Journal.h>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include <ripple/protocol/Feature.h>
|
#include <ripple/protocol/Feature.h>
|
||||||
#include <ripple/protocol/SystemParameters.h>
|
#include <ripple/protocol/SystemParameters.h>
|
||||||
#include <ripple/net/HTTPClient.h>
|
#include <ripple/net/HTTPClient.h>
|
||||||
#include <beast/http/URL.h>
|
#include <ripple/beast/net/URL.h>
|
||||||
#include <ripple/beast/core/LexicalCast.h>
|
#include <ripple/beast/core/LexicalCast.h>
|
||||||
#include <beast/streams/debug_ostream.h>
|
#include <beast/streams/debug_ostream.h>
|
||||||
#include <beast/ci_char_traits.h>
|
#include <beast/ci_char_traits.h>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public:
|
|||||||
virtual
|
virtual
|
||||||
Handoff
|
Handoff
|
||||||
onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) = 0;
|
boost::asio::ip::tcp::endpoint remote_address) = 0;
|
||||||
|
|
||||||
/** Establish a peer connection to the specified endpoint.
|
/** Establish a peer connection to the specified endpoint.
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ ConnectAttempt::onHandshake (error_code ec)
|
|||||||
if (! sharedValue)
|
if (! sharedValue)
|
||||||
return close(); // makeSharedValue logs
|
return close(); // makeSharedValue logs
|
||||||
|
|
||||||
beast::http::message req = makeRequest(
|
beast::deprecated_http::message req = makeRequest(
|
||||||
! overlay_.peerFinder().config().peerPrivate,
|
! overlay_.peerFinder().config().peerPrivate,
|
||||||
remote_endpoint_.address());
|
remote_endpoint_.address());
|
||||||
auto const hello = buildHello (
|
auto const hello = buildHello (
|
||||||
@@ -226,10 +226,9 @@ ConnectAttempt::onHandshake (error_code ec)
|
|||||||
overlay_.setup().public_ip,
|
overlay_.setup().public_ip,
|
||||||
beast::IPAddressConversion::from_asio(remote_endpoint_),
|
beast::IPAddressConversion::from_asio(remote_endpoint_),
|
||||||
app_);
|
app_);
|
||||||
appendHello (req, hello);
|
appendHello (req.headers, hello);
|
||||||
|
|
||||||
using beast::http::write;
|
beast::deprecated_http::write (write_buf_, req);
|
||||||
write (write_buf_, req);
|
|
||||||
|
|
||||||
setTimer();
|
setTimer();
|
||||||
stream_.async_write_some (write_buf_.data(),
|
stream_.async_write_some (write_buf_.data(),
|
||||||
@@ -293,10 +292,9 @@ ConnectAttempt::onRead (error_code ec, std::size_t bytes_transferred)
|
|||||||
|
|
||||||
if (! ec)
|
if (! ec)
|
||||||
{
|
{
|
||||||
write_buf_.commit (bytes_transferred);
|
write_buf_.commit(bytes_transferred);
|
||||||
std::size_t bytes_consumed;
|
auto bytes_consumed = parser_.write(
|
||||||
std::tie (ec, bytes_consumed) = parser_.write(
|
write_buf_.data(), ec);
|
||||||
write_buf_.data());
|
|
||||||
if (! ec)
|
if (! ec)
|
||||||
{
|
{
|
||||||
write_buf_.consume (bytes_consumed);
|
write_buf_.consume (bytes_consumed);
|
||||||
@@ -332,26 +330,26 @@ ConnectAttempt::onShutdown (error_code ec)
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
beast::http::message
|
beast::deprecated_http::message
|
||||||
ConnectAttempt::makeRequest (bool crawl,
|
ConnectAttempt::makeRequest (bool crawl,
|
||||||
boost::asio::ip::address const& remote_address)
|
boost::asio::ip::address const& remote_address)
|
||||||
{
|
{
|
||||||
beast::http::message m;
|
beast::deprecated_http::message m;
|
||||||
m.method (beast::http::method_t::http_get);
|
m.method (beast::http::method_t::http_get);
|
||||||
m.url ("/");
|
m.url ("/");
|
||||||
m.version (1, 1);
|
m.version (1, 1);
|
||||||
m.headers.append ("User-Agent", BuildInfo::getFullVersionString());
|
m.headers.insert ("User-Agent", BuildInfo::getFullVersionString());
|
||||||
m.headers.append ("Upgrade", "RTXP/1.2");
|
m.headers.insert ("Upgrade", "RTXP/1.2");
|
||||||
//std::string("RTXP/") + to_string (BuildInfo::getCurrentProtocol()));
|
//std::string("RTXP/") + to_string (BuildInfo::getCurrentProtocol()));
|
||||||
m.headers.append ("Connection", "Upgrade");
|
m.headers.insert ("Connection", "Upgrade");
|
||||||
m.headers.append ("Connect-As", "Peer");
|
m.headers.insert ("Connect-As", "Peer");
|
||||||
m.headers.append ("Crawl", crawl ? "public" : "private");
|
m.headers.insert ("Crawl", crawl ? "public" : "private");
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Streambuf>
|
template <class Streambuf>
|
||||||
void
|
void
|
||||||
ConnectAttempt::processResponse (beast::http::message const& m,
|
ConnectAttempt::processResponse (beast::deprecated_http::message const& m,
|
||||||
Streambuf const& body)
|
Streambuf const& body)
|
||||||
{
|
{
|
||||||
if (response_.status() == 503)
|
if (response_.status() == 503)
|
||||||
@@ -392,7 +390,7 @@ ConnectAttempt::processResponse (beast::http::message const& m,
|
|||||||
return close();
|
return close();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hello = parseHello (response_, journal_);
|
auto hello = parseHello (false, response_.headers, journal_);
|
||||||
if(! hello)
|
if(! hello)
|
||||||
return fail("processResponse: Bad TMHello");
|
return fail("processResponse: Bad TMHello");
|
||||||
|
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ private:
|
|||||||
beast::asio::ssl_bundle::stream_type& stream_;
|
beast::asio::ssl_bundle::stream_type& stream_;
|
||||||
beast::streambuf read_buf_;
|
beast::streambuf read_buf_;
|
||||||
beast::streambuf write_buf_;
|
beast::streambuf write_buf_;
|
||||||
beast::http::message response_;
|
beast::deprecated_http::message response_;
|
||||||
beast::streambuf body_;
|
beast::streambuf body_;
|
||||||
beast::http::parser parser_;
|
beast::deprecated_http::parser parser_;
|
||||||
PeerFinder::Slot::ptr slot_;
|
PeerFinder::Slot::ptr slot_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -100,12 +100,12 @@ private:
|
|||||||
void onShutdown (error_code ec);
|
void onShutdown (error_code ec);
|
||||||
|
|
||||||
static
|
static
|
||||||
beast::http::message
|
beast::deprecated_http::message
|
||||||
makeRequest (bool crawl,
|
makeRequest (bool crawl,
|
||||||
boost::asio::ip::address const& remote_address);
|
boost::asio::ip::address const& remote_address);
|
||||||
|
|
||||||
template <class Streambuf>
|
template <class Streambuf>
|
||||||
void processResponse (beast::http::message const& m,
|
void processResponse (beast::deprecated_http::message const& m,
|
||||||
Streambuf const& body);
|
Streambuf const& body);
|
||||||
|
|
||||||
template <class = void>
|
template <class = void>
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ OverlayImpl::~OverlayImpl ()
|
|||||||
|
|
||||||
Handoff
|
Handoff
|
||||||
OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
endpoint_type remote_endpoint)
|
endpoint_type remote_endpoint)
|
||||||
{
|
{
|
||||||
auto const id = next_id_++;
|
auto const id = next_id_++;
|
||||||
@@ -226,14 +226,14 @@ OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
|||||||
handoff.moved = false;
|
handoff.moved = false;
|
||||||
handoff.response = makeRedirectResponse(slot, request,
|
handoff.response = makeRedirectResponse(slot, request,
|
||||||
remote_endpoint.address());
|
remote_endpoint.address());
|
||||||
handoff.keep_alive = request.keep_alive();
|
handoff.keep_alive = is_keep_alive(request);
|
||||||
return handoff;
|
return handoff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handoff.moved = true;
|
handoff.moved = true;
|
||||||
|
|
||||||
auto hello = parseHello (request, journal);
|
auto hello = parseHello (true, request.headers, journal);
|
||||||
if(! hello)
|
if(! hello)
|
||||||
return handoff;
|
return handoff;
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
|||||||
handoff.moved = false;
|
handoff.moved = false;
|
||||||
handoff.response = makeRedirectResponse(slot, request,
|
handoff.response = makeRedirectResponse(slot, request,
|
||||||
remote_endpoint.address());
|
remote_endpoint.address());
|
||||||
handoff.keep_alive = request.keep_alive();
|
handoff.keep_alive = is_keep_alive(request);
|
||||||
return handoff;
|
return handoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +289,19 @@ OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OverlayImpl::isPeerUpgrade(beast::http::message const& request)
|
OverlayImpl::isPeerUpgrade(http_request_type const& request)
|
||||||
|
{
|
||||||
|
if (! is_upgrade(request))
|
||||||
|
return false;
|
||||||
|
auto const versions = parse_ProtocolVersions(
|
||||||
|
request.headers["Upgrade"]);
|
||||||
|
if (versions.size() == 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
OverlayImpl::isPeerUpgrade(beast::deprecated_http::message const& request)
|
||||||
{
|
{
|
||||||
if (! request.upgrade())
|
if (! request.upgrade())
|
||||||
return false;
|
return false;
|
||||||
@@ -297,7 +309,7 @@ OverlayImpl::isPeerUpgrade(beast::http::message const& request)
|
|||||||
request.headers["Upgrade"]);
|
request.headers["Upgrade"]);
|
||||||
if (versions.size() == 0)
|
if (versions.size() == 0)
|
||||||
return false;
|
return false;
|
||||||
if (! request.request() && request.status() != 101)
|
if(! request.request() && request.status() != 101)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -312,7 +324,7 @@ OverlayImpl::makePrefix (std::uint32_t id)
|
|||||||
|
|
||||||
std::shared_ptr<Writer>
|
std::shared_ptr<Writer>
|
||||||
OverlayImpl::makeRedirectResponse (PeerFinder::Slot::ptr const& slot,
|
OverlayImpl::makeRedirectResponse (PeerFinder::Slot::ptr const& slot,
|
||||||
beast::http::message const& request, address_type remote_address)
|
http_request_type const& request, address_type remote_address)
|
||||||
{
|
{
|
||||||
Json::Value json(Json::objectValue);
|
Json::Value json(Json::objectValue);
|
||||||
{
|
{
|
||||||
@@ -322,13 +334,13 @@ OverlayImpl::makeRedirectResponse (PeerFinder::Slot::ptr const& slot,
|
|||||||
ips.append(_.address.to_string());
|
ips.append(_.address.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
beast::http::message m;
|
beast::deprecated_http::message m;
|
||||||
m.request(false);
|
m.request(false);
|
||||||
m.status(503);
|
m.status(503);
|
||||||
m.reason("Service Unavailable");
|
m.reason("Service Unavailable");
|
||||||
m.headers.append("Remote-Address", remote_address.to_string());
|
m.headers.insert("Remote-Address", remote_address.to_string());
|
||||||
m.version(request.version());
|
m.version(std::make_pair(request.version / 10, request.version % 10));
|
||||||
if (request.version() == std::make_pair(1, 0))
|
if (request.version == 10)
|
||||||
{
|
{
|
||||||
//?
|
//?
|
||||||
}
|
}
|
||||||
@@ -829,16 +841,17 @@ OverlayImpl::json ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OverlayImpl::processRequest (beast::http::message const& req,
|
OverlayImpl::processRequest (http_request_type const& req,
|
||||||
Handoff& handoff)
|
Handoff& handoff)
|
||||||
{
|
{
|
||||||
if (req.url() != "/crawl")
|
if (req.url != "/crawl")
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
beast::http::message resp;
|
beast::deprecated_http::message resp;
|
||||||
resp.request(false);
|
resp.request(false);
|
||||||
resp.status(200);
|
resp.status(200);
|
||||||
resp.reason("OK");
|
resp.reason("OK");
|
||||||
|
resp.version(std::make_pair(req.version / 10, req.version % 10));
|
||||||
Json::Value v;
|
Json::Value v;
|
||||||
v["overlay"] = crawl();
|
v["overlay"] = crawl();
|
||||||
handoff.response = make_JsonWriter(resp, v);
|
handoff.response = make_JsonWriter(resp, v);
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ public:
|
|||||||
|
|
||||||
Handoff
|
Handoff
|
||||||
onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
endpoint_type remote_endpoint) override;
|
endpoint_type remote_endpoint) override;
|
||||||
|
|
||||||
PeerSequence
|
PeerSequence
|
||||||
@@ -254,7 +254,11 @@ public:
|
|||||||
|
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
isPeerUpgrade (beast::http::message const& request);
|
isPeerUpgrade (http_request_type const& request);
|
||||||
|
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
isPeerUpgrade (beast::deprecated_http::message const& request);
|
||||||
|
|
||||||
static
|
static
|
||||||
std::string
|
std::string
|
||||||
@@ -266,6 +270,18 @@ public:
|
|||||||
bool isInbound,
|
bool isInbound,
|
||||||
int bytes);
|
int bytes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Writer>
|
||||||
|
makeRedirectResponse (PeerFinder::Slot::ptr const& slot,
|
||||||
|
http_request_type const& request, address_type remote_address);
|
||||||
|
|
||||||
|
bool
|
||||||
|
processRequest (http_request_type const& req,
|
||||||
|
Handoff& handoff);
|
||||||
|
|
||||||
|
void
|
||||||
|
connect (beast::IP::Endpoint const& remote_endpoint) override;
|
||||||
|
|
||||||
/* The number of active peers on the network
|
/* The number of active peers on the network
|
||||||
Active peers are only those peers that have completed the handshake
|
Active peers are only those peers that have completed the handshake
|
||||||
and are running the Ripple protocol.
|
and are running the Ripple protocol.
|
||||||
@@ -282,18 +298,6 @@ public:
|
|||||||
Json::Value
|
Json::Value
|
||||||
json() override;
|
json() override;
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<Writer>
|
|
||||||
makeRedirectResponse (PeerFinder::Slot::ptr const& slot,
|
|
||||||
beast::http::message const& request, address_type remote_address);
|
|
||||||
|
|
||||||
void
|
|
||||||
connect (beast::IP::Endpoint const& remote_endpoint) override;
|
|
||||||
|
|
||||||
bool
|
|
||||||
processRequest (beast::http::message const& req,
|
|
||||||
Handoff& handoff);
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ using namespace std::chrono_literals;
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
PeerImp::PeerImp (Application& app, id_t id, endpoint_type remote_endpoint,
|
PeerImp::PeerImp (Application& app, id_t id, endpoint_type remote_endpoint,
|
||||||
PeerFinder::Slot::ptr const& slot, beast::http::message&& request,
|
PeerFinder::Slot::ptr const& slot, http_request_type&& request,
|
||||||
protocol::TMHello const& hello, PublicKey const& publicKey,
|
protocol::TMHello const& hello, PublicKey const& publicKey,
|
||||||
Resource::Consumer consumer,
|
Resource::Consumer consumer,
|
||||||
std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
||||||
@@ -89,7 +89,8 @@ PeerImp::PeerImp (Application& app, id_t id, endpoint_type remote_endpoint,
|
|||||||
, usage_(consumer)
|
, usage_(consumer)
|
||||||
, fee_ (Resource::feeLightPeer)
|
, fee_ (Resource::feeLightPeer)
|
||||||
, slot_ (slot)
|
, slot_ (slot)
|
||||||
, http_message_(std::move(request))
|
, request_(std::move(request))
|
||||||
|
, headers_(request_.headers)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,8 +238,8 @@ PeerImp::charge (Resource::Charge const& fee)
|
|||||||
bool
|
bool
|
||||||
PeerImp::crawl() const
|
PeerImp::crawl() const
|
||||||
{
|
{
|
||||||
auto const iter = http_message_.headers.find("Crawl");
|
auto const iter = headers_.find("Crawl");
|
||||||
if (iter == http_message_.headers.end())
|
if (iter == headers_.end())
|
||||||
return false;
|
return false;
|
||||||
return beast::ci_equal(iter->second, "public");
|
return beast::ci_equal(iter->second, "public");
|
||||||
}
|
}
|
||||||
@@ -586,7 +587,7 @@ PeerImp::onShutdown(error_code ec)
|
|||||||
void PeerImp::doAccept()
|
void PeerImp::doAccept()
|
||||||
{
|
{
|
||||||
assert(read_buffer_.size() == 0);
|
assert(read_buffer_.size() == 0);
|
||||||
assert(http_message_.upgrade());
|
// assert(request_.upgrade);
|
||||||
|
|
||||||
JLOG(journal_.debug()) << "doAccept: " << remote_address_;
|
JLOG(journal_.debug()) << "doAccept: " << remote_address_;
|
||||||
|
|
||||||
@@ -601,8 +602,8 @@ void PeerImp::doAccept()
|
|||||||
|
|
||||||
auto resp = makeResponse(
|
auto resp = makeResponse(
|
||||||
! overlay_.peerFinder().config().peerPrivate,
|
! overlay_.peerFinder().config().peerPrivate,
|
||||||
http_message_, remote_address_, *sharedValue);
|
request_, remote_address_, *sharedValue);
|
||||||
beast::http::write (write_buffer_, resp);
|
beast::deprecated_http::write (write_buffer_, resp);
|
||||||
|
|
||||||
auto const protocol = BuildInfo::make_protocol(hello_.protoversion());
|
auto const protocol = BuildInfo::make_protocol(hello_.protoversion());
|
||||||
JLOG(journal_.info()) << "Protocol: " << to_string(protocol);
|
JLOG(journal_.info()) << "Protocol: " << to_string(protocol);
|
||||||
@@ -641,25 +642,25 @@ void PeerImp::doAccept()
|
|||||||
onWriteResponse(error_code(), 0);
|
onWriteResponse(error_code(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
beast::http::message
|
beast::deprecated_http::message
|
||||||
PeerImp::makeResponse (bool crawl,
|
PeerImp::makeResponse (bool crawl,
|
||||||
beast::http::message const& req,
|
http_request_type const& req,
|
||||||
beast::IP::Endpoint remote,
|
beast::IP::Endpoint remote,
|
||||||
uint256 const& sharedValue)
|
uint256 const& sharedValue)
|
||||||
{
|
{
|
||||||
beast::http::message resp;
|
beast::deprecated_http::message resp;
|
||||||
resp.request(false);
|
resp.request(false);
|
||||||
resp.status(101);
|
resp.status(101);
|
||||||
resp.reason("Switching Protocols");
|
resp.reason("Switching Protocols");
|
||||||
resp.version(req.version());
|
resp.version(std::make_pair(req.version / 10, req.version % 10));
|
||||||
resp.headers.append("Connection", "Upgrade");
|
resp.headers.insert("Connection", "Upgrade");
|
||||||
resp.headers.append("Upgrade", "RTXP/1.2");
|
resp.headers.insert("Upgrade", "RTXP/1.2");
|
||||||
resp.headers.append("Connect-AS", "Peer");
|
resp.headers.insert("Connect-AS", "Peer");
|
||||||
resp.headers.append("Server", BuildInfo::getFullVersionString());
|
resp.headers.insert("Server", BuildInfo::getFullVersionString());
|
||||||
resp.headers.append ("Crawl", crawl ? "public" : "private");
|
resp.headers.insert("Crawl", crawl ? "public" : "private");
|
||||||
protocol::TMHello hello = buildHello(sharedValue,
|
protocol::TMHello hello = buildHello(sharedValue,
|
||||||
overlay_.setup().public_ip, remote, app_);
|
overlay_.setup().public_ip, remote, app_);
|
||||||
appendHello(resp, hello);
|
appendHello(resp.headers, hello);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,8 +153,9 @@ private:
|
|||||||
Resource::Charge fee_;
|
Resource::Charge fee_;
|
||||||
PeerFinder::Slot::ptr slot_;
|
PeerFinder::Slot::ptr slot_;
|
||||||
beast::streambuf read_buffer_;
|
beast::streambuf read_buffer_;
|
||||||
beast::http::message http_message_;
|
http_request_type request_;
|
||||||
beast::http::body http_body_;
|
beast::deprecated_http::message response_;
|
||||||
|
beast::http::headers<std::allocator<char>> const& headers_;
|
||||||
beast::streambuf write_buffer_;
|
beast::streambuf write_buffer_;
|
||||||
std::queue<Message::pointer> send_queue_;
|
std::queue<Message::pointer> send_queue_;
|
||||||
bool gracefulClose_ = false;
|
bool gracefulClose_ = false;
|
||||||
@@ -171,7 +172,7 @@ public:
|
|||||||
|
|
||||||
/** Create an active incoming peer from an established ssl connection. */
|
/** Create an active incoming peer from an established ssl connection. */
|
||||||
PeerImp (Application& app, id_t id, endpoint_type remote_endpoint,
|
PeerImp (Application& app, id_t id, endpoint_type remote_endpoint,
|
||||||
PeerFinder::Slot::ptr const& slot, beast::http::message&& request,
|
PeerFinder::Slot::ptr const& slot, http_request_type&& request,
|
||||||
protocol::TMHello const& hello, PublicKey const& publicKey,
|
protocol::TMHello const& hello, PublicKey const& publicKey,
|
||||||
Resource::Consumer consumer,
|
Resource::Consumer consumer,
|
||||||
std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
||||||
@@ -182,7 +183,7 @@ public:
|
|||||||
template <class Buffers>
|
template <class Buffers>
|
||||||
PeerImp (Application& app, std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
PeerImp (Application& app, std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
||||||
Buffers const& buffers, PeerFinder::Slot::ptr&& slot,
|
Buffers const& buffers, PeerFinder::Slot::ptr&& slot,
|
||||||
beast::http::message&& response, Resource::Consumer usage,
|
beast::deprecated_http::message&& response, Resource::Consumer usage,
|
||||||
protocol::TMHello const& hello,
|
protocol::TMHello const& hello,
|
||||||
PublicKey const& publicKey, id_t id,
|
PublicKey const& publicKey, id_t id,
|
||||||
OverlayImpl& overlay);
|
OverlayImpl& overlay);
|
||||||
@@ -359,8 +360,8 @@ private:
|
|||||||
void
|
void
|
||||||
doAccept();
|
doAccept();
|
||||||
|
|
||||||
beast::http::message
|
beast::deprecated_http::message
|
||||||
makeResponse (bool crawl, beast::http::message const& req,
|
makeResponse (bool crawl, http_request_type const& req,
|
||||||
beast::IP::Endpoint remoteAddress,
|
beast::IP::Endpoint remoteAddress,
|
||||||
uint256 const& sharedValue);
|
uint256 const& sharedValue);
|
||||||
|
|
||||||
@@ -476,7 +477,7 @@ private:
|
|||||||
template <class Buffers>
|
template <class Buffers>
|
||||||
PeerImp::PeerImp (Application& app, std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
PeerImp::PeerImp (Application& app, std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
||||||
Buffers const& buffers, PeerFinder::Slot::ptr&& slot,
|
Buffers const& buffers, PeerFinder::Slot::ptr&& slot,
|
||||||
beast::http::message&& response, Resource::Consumer usage,
|
beast::deprecated_http::message&& response, Resource::Consumer usage,
|
||||||
protocol::TMHello const& hello,
|
protocol::TMHello const& hello,
|
||||||
PublicKey const& publicKey, id_t id,
|
PublicKey const& publicKey, id_t id,
|
||||||
OverlayImpl& overlay)
|
OverlayImpl& overlay)
|
||||||
@@ -504,7 +505,8 @@ PeerImp::PeerImp (Application& app, std::unique_ptr<beast::asio::ssl_bundle>&& s
|
|||||||
, usage_ (usage)
|
, usage_ (usage)
|
||||||
, fee_ (Resource::feeLightPeer)
|
, fee_ (Resource::feeLightPeer)
|
||||||
, slot_ (std::move(slot))
|
, slot_ (std::move(slot))
|
||||||
, http_message_(std::move(response))
|
, response_(std::move(response))
|
||||||
|
, headers_(response_.headers)
|
||||||
{
|
{
|
||||||
read_buffer_.commit (boost::asio::buffer_copy(read_buffer_.prepare(
|
read_buffer_.commit (boost::asio::buffer_copy(read_buffer_.prepare(
|
||||||
boost::asio::buffer_size(buffers)), buffers));
|
boost::asio::buffer_size(buffers)), buffers));
|
||||||
|
|||||||
@@ -154,43 +154,41 @@ buildHello (
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
appendHello (beast::http::message& m,
|
appendHello (beast::http::headers<std::allocator<char>>& h,
|
||||||
protocol::TMHello const& hello)
|
protocol::TMHello const& hello)
|
||||||
{
|
{
|
||||||
auto& h = m.headers;
|
|
||||||
|
|
||||||
//h.append ("Protocol-Versions",...
|
//h.append ("Protocol-Versions",...
|
||||||
|
|
||||||
h.append ("Public-Key", hello.nodepublic());
|
h.insert ("Public-Key", hello.nodepublic());
|
||||||
|
|
||||||
h.append ("Session-Signature", beast::base64_encode (
|
h.insert ("Session-Signature", beast::base64_encode (
|
||||||
hello.nodeproof()));
|
hello.nodeproof()));
|
||||||
|
|
||||||
if (hello.has_nettime())
|
if (hello.has_nettime())
|
||||||
h.append ("Network-Time", std::to_string (hello.nettime()));
|
h.insert ("Network-Time", std::to_string (hello.nettime()));
|
||||||
|
|
||||||
if (hello.has_ledgerindex())
|
if (hello.has_ledgerindex())
|
||||||
h.append ("Ledger", std::to_string (hello.ledgerindex()));
|
h.insert ("Ledger", std::to_string (hello.ledgerindex()));
|
||||||
|
|
||||||
if (hello.has_ledgerclosed())
|
if (hello.has_ledgerclosed())
|
||||||
h.append ("Closed-Ledger", beast::base64_encode (
|
h.insert ("Closed-Ledger", beast::base64_encode (
|
||||||
hello.ledgerclosed()));
|
hello.ledgerclosed()));
|
||||||
|
|
||||||
if (hello.has_ledgerprevious())
|
if (hello.has_ledgerprevious())
|
||||||
h.append ("Previous-Ledger", beast::base64_encode (
|
h.insert ("Previous-Ledger", beast::base64_encode (
|
||||||
hello.ledgerprevious()));
|
hello.ledgerprevious()));
|
||||||
|
|
||||||
if (hello.has_local_ip())
|
if (hello.has_local_ip())
|
||||||
h.append ("Local-IP", beast::IP::to_string (
|
h.insert ("Local-IP", beast::IP::to_string (
|
||||||
beast::IP::AddressV4(hello.local_ip())));
|
beast::IP::AddressV4(hello.local_ip())));
|
||||||
|
|
||||||
if (hello.has_remote_ip())
|
if (hello.has_remote_ip())
|
||||||
h.append ("Remote-IP", beast::IP::to_string (
|
h.insert ("Remote-IP", beast::IP::to_string (
|
||||||
beast::IP::AddressV4(hello.remote_ip())));
|
beast::IP::AddressV4(hello.remote_ip())));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ProtocolVersion>
|
std::vector<ProtocolVersion>
|
||||||
parse_ProtocolVersions (std::string const& s)
|
parse_ProtocolVersions(boost::string_ref const& value)
|
||||||
{
|
{
|
||||||
static boost::regex re (
|
static boost::regex re (
|
||||||
"^" // start of line
|
"^" // start of line
|
||||||
@@ -201,7 +199,7 @@ parse_ProtocolVersions (std::string const& s)
|
|||||||
"$" // The end of the string
|
"$" // The end of the string
|
||||||
, boost::regex_constants::optimize);
|
, boost::regex_constants::optimize);
|
||||||
|
|
||||||
auto const list = beast::rfc2616::split_commas (s);
|
auto const list = beast::rfc2616::split_commas(value);
|
||||||
std::vector<ProtocolVersion> result;
|
std::vector<ProtocolVersion> result;
|
||||||
for (auto const& s : list)
|
for (auto const& s : list)
|
||||||
{
|
{
|
||||||
@@ -224,10 +222,8 @@ parse_ProtocolVersions (std::string const& s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<protocol::TMHello>
|
boost::optional<protocol::TMHello>
|
||||||
parseHello (beast::http::message const& m, beast::Journal journal)
|
parseHello (bool request, beast::http::headers<std::allocator<char>> const& h, beast::Journal journal)
|
||||||
{
|
{
|
||||||
auto const& h = m.headers;
|
|
||||||
|
|
||||||
// protocol version in TMHello is obsolete,
|
// protocol version in TMHello is obsolete,
|
||||||
// it is supplanted by the values in the headers.
|
// it is supplanted by the values in the headers.
|
||||||
protocol::TMHello hello;
|
protocol::TMHello hello;
|
||||||
@@ -270,7 +266,7 @@ parseHello (beast::http::message const& m, beast::Journal journal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto const iter = h.find (m.request() ?
|
auto const iter = h.find (request ?
|
||||||
"User-Agent" : "Server");
|
"User-Agent" : "Server");
|
||||||
if (iter != h.end())
|
if (iter != h.end())
|
||||||
hello.set_fullversion (iter->second);
|
hello.set_fullversion (iter->second);
|
||||||
|
|||||||
@@ -27,10 +27,9 @@
|
|||||||
#include <beast/http/message.h>
|
#include <beast/http/message.h>
|
||||||
#include <ripple/beast/utility/Journal.h>
|
#include <ripple/beast/utility/Journal.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <boost/asio/ssl.hpp>
|
#include <boost/asio/ssl.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/utility/string_ref.hpp>
|
||||||
#include "ripple.pb.h"
|
#include "ripple.pb.h"
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -59,14 +58,14 @@ buildHello (uint256 const& sharedValue,
|
|||||||
|
|
||||||
/** Insert HTTP headers based on the TMHello protocol message. */
|
/** Insert HTTP headers based on the TMHello protocol message. */
|
||||||
void
|
void
|
||||||
appendHello (beast::http::message& m, protocol::TMHello const& hello);
|
appendHello (beast::http::headers<std::allocator<char>>& h, protocol::TMHello const& hello);
|
||||||
|
|
||||||
/** Parse HTTP headers into TMHello protocol message.
|
/** Parse HTTP headers into TMHello protocol message.
|
||||||
@return A protocol message on success; an empty optional
|
@return A protocol message on success; an empty optional
|
||||||
if the parsing failed.
|
if the parsing failed.
|
||||||
*/
|
*/
|
||||||
boost::optional<protocol::TMHello>
|
boost::optional<protocol::TMHello>
|
||||||
parseHello (beast::http::message const& m, beast::Journal journal);
|
parseHello (bool request, beast::http::headers<std::allocator<char>> const& h, beast::Journal journal);
|
||||||
|
|
||||||
/** Validate and store the public key in the TMHello.
|
/** Validate and store the public key in the TMHello.
|
||||||
This includes signature verification on the shared value.
|
This includes signature verification on the shared value.
|
||||||
@@ -85,7 +84,7 @@ verifyHello (protocol::TMHello const& h, uint256 const& sharedValue,
|
|||||||
excluded from the result set.
|
excluded from the result set.
|
||||||
*/
|
*/
|
||||||
std::vector<ProtocolVersion>
|
std::vector<ProtocolVersion>
|
||||||
parse_ProtocolVersions (std::string const& s);
|
parse_ProtocolVersions(boost::string_ref const& s);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include <ripple/server/Handoff.h>
|
#include <ripple/server/Handoff.h>
|
||||||
#include <beast/asio/ssl_bundle.h>
|
#include <beast/asio/ssl_bundle.h>
|
||||||
#include <beast/http/message.h>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
@@ -61,18 +60,18 @@ struct Handler
|
|||||||
Handoff
|
Handoff
|
||||||
onHandoff (Session& session,
|
onHandoff (Session& session,
|
||||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) = 0;
|
boost::asio::ip::tcp::endpoint remote_address) = 0;
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
Handoff
|
Handoff
|
||||||
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) = 0;
|
boost::asio::ip::tcp::endpoint remote_address) = 0;
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/** Called when we have a complete HTTP request. */
|
/** Called when we have a complete HTTP request. */
|
||||||
// VFALCO TODO Pass the beast::http::message as a parameter
|
// VFALCO TODO Pass the beast::deprecated_http::message as a parameter
|
||||||
virtual void onRequest (Session& session) = 0;
|
virtual void onRequest (Session& session) = 0;
|
||||||
|
|
||||||
/** Called when the session ends.
|
/** Called when the session ends.
|
||||||
|
|||||||
@@ -21,10 +21,15 @@
|
|||||||
#define RIPPLE_SERVER_HANDOFF_H_INCLUDED
|
#define RIPPLE_SERVER_HANDOFF_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/server/Writer.h>
|
#include <ripple/server/Writer.h>
|
||||||
|
#include <beast/http/message.h>
|
||||||
|
#include <beast/http/streambuf_body.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
using http_request_type =
|
||||||
|
beast::http::request<beast::http::streambuf_body>;
|
||||||
|
|
||||||
/** Used to indicate the result of a server connection handoff. */
|
/** Used to indicate the result of a server connection handoff. */
|
||||||
struct Handoff
|
struct Handoff
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -144,16 +144,16 @@ write(Streambuf& buf, Json::Value const& json)
|
|||||||
*/
|
*/
|
||||||
template <class = void>
|
template <class = void>
|
||||||
std::shared_ptr<Writer>
|
std::shared_ptr<Writer>
|
||||||
make_JsonWriter (beast::http::message& m, Json::Value const& json)
|
make_JsonWriter (beast::deprecated_http::message& m, Json::Value const& json)
|
||||||
{
|
{
|
||||||
beast::streambuf prebody;
|
beast::streambuf prebody;
|
||||||
beast::streambuf body;
|
beast::streambuf body;
|
||||||
write(body, json);
|
write(body, json);
|
||||||
// VFALCO TODO Better way to set a field
|
// VFALCO TODO Better way to set a field
|
||||||
m.headers.erase ("Content-Length");
|
m.headers.erase ("Content-Length");
|
||||||
m.headers.append("Content-Length", std::to_string(body.size()));
|
m.headers.insert("Content-Length", std::to_string(body.size()));
|
||||||
m.headers.erase ("Content-Type");
|
m.headers.erase ("Content-Type");
|
||||||
m.headers.append("Content-Type", "application/json");
|
m.headers.insert("Content-Type", "application/json");
|
||||||
write(prebody, m);
|
write(prebody, m);
|
||||||
return std::make_shared<streambufs_writer>(
|
return std::make_shared<streambufs_writer>(
|
||||||
std::move(prebody), std::move(body));
|
std::move(prebody), std::move(body));
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public:
|
|||||||
/** Fills in boilerplate HTTP header field values. */
|
/** Fills in boilerplate HTTP header field values. */
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
appendStandardFields (beast::http::message& message);
|
appendStandardFields (beast::deprecated_http::message& message);
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -66,14 +66,9 @@ public:
|
|||||||
|
|
||||||
/** Returns the current HTTP request. */
|
/** Returns the current HTTP request. */
|
||||||
virtual
|
virtual
|
||||||
beast::http::message&
|
http_request_type&
|
||||||
request() = 0;
|
request() = 0;
|
||||||
|
|
||||||
/** Returns the Content-Body of the current HTTP request. */
|
|
||||||
virtual
|
|
||||||
beast::http::body const&
|
|
||||||
body() = 0;
|
|
||||||
|
|
||||||
/** Send a copy of data asynchronously. */
|
/** Send a copy of data asynchronously. */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -28,8 +28,10 @@
|
|||||||
#include <ripple/beast/net/IPAddressConversion.h>
|
#include <ripple/beast/net/IPAddressConversion.h>
|
||||||
#include <beast/asio/placeholders.h>
|
#include <beast/asio/placeholders.h>
|
||||||
#include <beast/asio/ssl_error.h> // for is_short_read?
|
#include <beast/asio/ssl_error.h> // for is_short_read?
|
||||||
|
#include <beast/http/read.h>
|
||||||
#include <beast/http/message.h>
|
#include <beast/http/message.h>
|
||||||
#include <beast/http/parser.h>
|
#include <beast/http/parser.h>
|
||||||
|
#include <beast/http/streambuf_body.h>
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
#include <boost/asio/ssl/stream.hpp>
|
#include <boost/asio/ssl/stream.hpp>
|
||||||
#include <boost/asio/streambuf.hpp>
|
#include <boost/asio/streambuf.hpp>
|
||||||
@@ -95,8 +97,7 @@ protected:
|
|||||||
std::size_t nid_;
|
std::size_t nid_;
|
||||||
|
|
||||||
boost::asio::streambuf read_buf_;
|
boost::asio::streambuf read_buf_;
|
||||||
beast::http::message message_;
|
http_request_type message_;
|
||||||
beast::http::body body_;
|
|
||||||
std::vector<buffer> wq_;
|
std::vector<buffer> wq_;
|
||||||
std::vector<buffer> wq2_;
|
std::vector<buffer> wq2_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
@@ -186,18 +187,12 @@ protected:
|
|||||||
return beast::IPAddressConversion::from_asio(remote_address_);
|
return beast::IPAddressConversion::from_asio(remote_address_);
|
||||||
}
|
}
|
||||||
|
|
||||||
beast::http::message&
|
http_request_type&
|
||||||
request() override
|
request() override
|
||||||
{
|
{
|
||||||
return message_;
|
return message_;
|
||||||
}
|
}
|
||||||
|
|
||||||
beast::http::body const&
|
|
||||||
body() override
|
|
||||||
{
|
|
||||||
return body_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
write (void const* buffer, std::size_t bytes) override;
|
write (void const* buffer, std::size_t bytes) override;
|
||||||
|
|
||||||
@@ -319,64 +314,12 @@ void
|
|||||||
BaseHTTPPeer<Impl>::do_read (yield_context yield)
|
BaseHTTPPeer<Impl>::do_read (yield_context yield)
|
||||||
{
|
{
|
||||||
complete_ = false;
|
complete_ = false;
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
bool eof = false;
|
beast::http::async_read(impl().stream_,
|
||||||
body_.clear();
|
read_buf_, message_, yield[ec]);
|
||||||
beast::http::parser parser (message_, body_, true);
|
// VFALCO What if the connection was closed?
|
||||||
for(;;)
|
cancel_timer();
|
||||||
{
|
do_request();
|
||||||
if (read_buf_.size() == 0)
|
|
||||||
{
|
|
||||||
start_timer();
|
|
||||||
auto const bytes_transferred = boost::asio::async_read (
|
|
||||||
impl().stream_, read_buf_.prepare (bufferSize),
|
|
||||||
boost::asio::transfer_at_least(1), yield[ec]);
|
|
||||||
cancel_timer();
|
|
||||||
|
|
||||||
eof = ec == boost::asio::error::eof;
|
|
||||||
if (eof)
|
|
||||||
{
|
|
||||||
ec = error_code{};
|
|
||||||
}
|
|
||||||
else if (! ec)
|
|
||||||
{
|
|
||||||
bytes_in_ += bytes_transferred;
|
|
||||||
read_buf_.commit (bytes_transferred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! ec)
|
|
||||||
{
|
|
||||||
if (! eof)
|
|
||||||
{
|
|
||||||
// VFALCO TODO Currently parsing errors are treated the
|
|
||||||
// same as the connection dropping. Instead, we
|
|
||||||
// should request that the handler compose a proper HTTP error
|
|
||||||
// response. This requires refactoring HTTPReply() into
|
|
||||||
// something sensible.
|
|
||||||
std::size_t used;
|
|
||||||
std::tie (ec, used) = parser.write (read_buf_.data());
|
|
||||||
if (! ec)
|
|
||||||
read_buf_.consume (used);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ec = parser.write_eof();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! ec)
|
|
||||||
{
|
|
||||||
if (parser.complete())
|
|
||||||
return do_request();
|
|
||||||
if (eof)
|
|
||||||
ec = boost::asio::error::eof; // incomplete request
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ec)
|
|
||||||
return fail (ec, "read");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send everything in the write queue.
|
// Send everything in the write queue.
|
||||||
@@ -513,7 +456,7 @@ BaseHTTPPeer<Impl>::complete()
|
|||||||
return strand_.post(std::bind (&BaseHTTPPeer<Impl>::complete,
|
return strand_.post(std::bind (&BaseHTTPPeer<Impl>::complete,
|
||||||
impl().shared_from_this()));
|
impl().shared_from_this()));
|
||||||
|
|
||||||
message_ = beast::http::message{};
|
message_ = {};
|
||||||
complete_ = true;
|
complete_ = true;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ PlainHTTPPeer::do_request()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform half-close when Connection: close and not SSL
|
// Perform half-close when Connection: close and not SSL
|
||||||
if (! message_.keep_alive())
|
if (! is_keep_alive(message_))
|
||||||
stream_.shutdown (socket_type::shutdown_receive, ec);
|
stream_.shutdown (socket_type::shutdown_receive, ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
return fail (ec, "request");
|
return fail (ec, "request");
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include <ripple/server/Port.h>
|
#include <ripple/server/Port.h>
|
||||||
#include <beast/http/rfc2616.h>
|
#include <beast/http/rfc2616.h>
|
||||||
#include <beast/module/core/text/LexicalCast.h>
|
#include <ripple/beast/core/LexicalCast.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ parse_Port (ParsedPort& port, Section const& section, std::ostream& log)
|
|||||||
if (*port.port == 0)
|
if (*port.port == 0)
|
||||||
Throw<std::exception> ();
|
Throw<std::exception> ();
|
||||||
}
|
}
|
||||||
catch (std::exception const& ex)
|
catch (std::exception const&)
|
||||||
{
|
{
|
||||||
log <<
|
log <<
|
||||||
"Invalid value '" << result.first << "' for key " <<
|
"Invalid value '" << result.first << "' for key " <<
|
||||||
@@ -199,7 +199,7 @@ parse_Port (ParsedPort& port, Section const& section, std::ostream& log)
|
|||||||
port.limit = static_cast<int> (
|
port.limit = static_cast<int> (
|
||||||
beast::lexicalCastThrow<std::uint16_t>(lim));
|
beast::lexicalCastThrow<std::uint16_t>(lim));
|
||||||
}
|
}
|
||||||
catch (std::exception const& ex)
|
catch (std::exception const&)
|
||||||
{
|
{
|
||||||
log <<
|
log <<
|
||||||
"Invalid value '" << lim << "' for key " <<
|
"Invalid value '" << lim << "' for key " <<
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ ServerHandlerImp::onAccept (Session& session,
|
|||||||
auto
|
auto
|
||||||
ServerHandlerImp::onHandoff (Session& session,
|
ServerHandlerImp::onHandoff (Session& session,
|
||||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) ->
|
boost::asio::ip::tcp::endpoint remote_address) ->
|
||||||
Handoff
|
Handoff
|
||||||
{
|
{
|
||||||
@@ -138,7 +138,7 @@ ServerHandlerImp::onHandoff (Session& session,
|
|||||||
auto
|
auto
|
||||||
ServerHandlerImp::onHandoff (Session& session,
|
ServerHandlerImp::onHandoff (Session& session,
|
||||||
boost::asio::ip::tcp::socket&& socket,
|
boost::asio::ip::tcp::socket&& socket,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) ->
|
boost::asio::ip::tcp::endpoint remote_address) ->
|
||||||
Handoff
|
Handoff
|
||||||
{
|
{
|
||||||
@@ -163,6 +163,23 @@ Json::Output makeOutput (Session& session)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HACK!
|
||||||
|
template<class Allocator>
|
||||||
|
static
|
||||||
|
std::map<std::string, std::string>
|
||||||
|
build_map(beast::http::headers<Allocator> const& h)
|
||||||
|
{
|
||||||
|
std::map <std::string, std::string> c;
|
||||||
|
for (auto const& e : h)
|
||||||
|
{
|
||||||
|
auto key (e.first);
|
||||||
|
// TODO Replace with safe C++14 version
|
||||||
|
std::transform (key.begin(), key.end(), key.begin(), ::tolower);
|
||||||
|
c [key] = e.second;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ServerHandlerImp::onRequest (Session& session)
|
ServerHandlerImp::onRequest (Session& session)
|
||||||
{
|
{
|
||||||
@@ -207,12 +224,32 @@ ServerHandlerImp::onStopped (Server&)
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
buffers_to_string(ConstBufferSequence const& bs)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string s;
|
||||||
|
s.reserve(buffer_size(bs));
|
||||||
|
for(auto const& b : bs)
|
||||||
|
s.append(buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b));
|
||||||
|
for(auto i = s.size(); i-- > 0;)
|
||||||
|
if(s[i] == '\r')
|
||||||
|
s.replace(i, 1, "\\r");
|
||||||
|
else if(s[i] == '\n')
|
||||||
|
s.replace(i, 1, "\\n\n");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
// Run as a couroutine.
|
// Run as a couroutine.
|
||||||
void
|
void
|
||||||
ServerHandlerImp::processSession (std::shared_ptr<Session> const& session,
|
ServerHandlerImp::processSession (std::shared_ptr<Session> const& session,
|
||||||
std::shared_ptr<JobCoro> jobCoro)
|
std::shared_ptr<JobCoro> jobCoro)
|
||||||
{
|
{
|
||||||
processRequest (session->port(), to_string (session->body()),
|
processRequest (session->port(), buffers_to_string(session->request().body.data()),
|
||||||
session->remoteAddress().at_port (0), makeOutput (*session), jobCoro,
|
session->remoteAddress().at_port (0), makeOutput (*session), jobCoro,
|
||||||
[&]
|
[&]
|
||||||
{
|
{
|
||||||
@@ -233,7 +270,7 @@ ServerHandlerImp::processSession (std::shared_ptr<Session> const& session,
|
|||||||
return std::string{};
|
return std::string{};
|
||||||
}());
|
}());
|
||||||
|
|
||||||
if (session->request().keep_alive())
|
if(is_keep_alive(session->request()))
|
||||||
session->complete();
|
session->complete();
|
||||||
else
|
else
|
||||||
session->close (true);
|
session->close (true);
|
||||||
@@ -425,9 +462,9 @@ ServerHandlerImp::processRequest (Port const& port,
|
|||||||
// Returns `true` if the HTTP request is a Websockets Upgrade
|
// Returns `true` if the HTTP request is a Websockets Upgrade
|
||||||
// http://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header#Use_with_WebSockets
|
// http://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header#Use_with_WebSockets
|
||||||
bool
|
bool
|
||||||
ServerHandlerImp::isWebsocketUpgrade (beast::http::message const& request)
|
ServerHandlerImp::isWebsocketUpgrade (http_request_type const& request)
|
||||||
{
|
{
|
||||||
if (request.upgrade())
|
if (is_upgrade(request))
|
||||||
return request.headers["Upgrade"] == "websocket";
|
return request.headers["Upgrade"] == "websocket";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -457,7 +494,7 @@ ServerHandlerImp::authorized (Port const& port,
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
ServerHandler::appendStandardFields (beast::http::message& message)
|
ServerHandler::appendStandardFields (beast::deprecated_http::message& message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,12 +95,12 @@ private:
|
|||||||
Handoff
|
Handoff
|
||||||
onHandoff (Session& session,
|
onHandoff (Session& session,
|
||||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) override;
|
boost::asio::ip::tcp::endpoint remote_address) override;
|
||||||
|
|
||||||
Handoff
|
Handoff
|
||||||
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) override;
|
boost::asio::ip::tcp::endpoint remote_address) override;
|
||||||
void
|
void
|
||||||
onRequest (Session& session) override;
|
onRequest (Session& session) override;
|
||||||
@@ -126,7 +126,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool
|
bool
|
||||||
isWebsocketUpgrade (beast::http::message const& request);
|
isWebsocketUpgrade (http_request_type const& request);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
authorized (Port const& port,
|
authorized (Port const& port,
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ public:
|
|||||||
Handoff
|
Handoff
|
||||||
onHandoff (Session& session,
|
onHandoff (Session& session,
|
||||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) override
|
boost::asio::ip::tcp::endpoint remote_address) override
|
||||||
{
|
{
|
||||||
return Handoff{};
|
return Handoff{};
|
||||||
@@ -115,7 +115,7 @@ public:
|
|||||||
|
|
||||||
Handoff
|
Handoff
|
||||||
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) override
|
boost::asio::ip::tcp::endpoint remote_address) override
|
||||||
{
|
{
|
||||||
return Handoff{};
|
return Handoff{};
|
||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
onRequest (Session& session) override
|
onRequest (Session& session) override
|
||||||
{
|
{
|
||||||
session.write (std::string ("Hello, world!\n"));
|
session.write (std::string ("Hello, world!\n"));
|
||||||
if (session.request().keep_alive())
|
if (is_keep_alive(session.request()))
|
||||||
session.complete();
|
session.complete();
|
||||||
else
|
else
|
||||||
session.close (true);
|
session.close (true);
|
||||||
@@ -309,7 +309,7 @@ public:
|
|||||||
Handoff
|
Handoff
|
||||||
onHandoff (Session& session,
|
onHandoff (Session& session,
|
||||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) override
|
boost::asio::ip::tcp::endpoint remote_address) override
|
||||||
{
|
{
|
||||||
return Handoff{};
|
return Handoff{};
|
||||||
@@ -317,7 +317,7 @@ public:
|
|||||||
|
|
||||||
Handoff
|
Handoff
|
||||||
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
||||||
beast::http::message&& request,
|
http_request_type&& request,
|
||||||
boost::asio::ip::tcp::endpoint remote_address) override
|
boost::asio::ip::tcp::endpoint remote_address) override
|
||||||
{
|
{
|
||||||
return Handoff{};
|
return Handoff{};
|
||||||
|
|||||||
@@ -122,8 +122,8 @@ public:
|
|||||||
|
|
||||||
read_until(stream_, bin_, "\r\n\r\n");
|
read_until(stream_, bin_, "\r\n\r\n");
|
||||||
beast::streambuf body;
|
beast::streambuf body;
|
||||||
beast::http::message m;
|
beast::deprecated_http::message m;
|
||||||
beast::http::parser p(
|
beast::deprecated_http::parser p(
|
||||||
[&](void const* data, std::size_t size)
|
[&](void const* data, std::size_t size)
|
||||||
{
|
{
|
||||||
body.commit(buffer_copy(
|
body.commit(buffer_copy(
|
||||||
@@ -132,11 +132,12 @@ public:
|
|||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
auto const result = p.write(bin_.data());
|
boost::system::error_code ec;
|
||||||
if (result.first)
|
auto used = p.write(bin_.data(), ec);
|
||||||
Throw<boost::system::system_error>(result.first);
|
if(ec)
|
||||||
|
Throw<boost::system::system_error>(ec);
|
||||||
bin_.consume(result.second);
|
bin_.consume(used);
|
||||||
|
// VFALCO What do we do if bin_ still has data?
|
||||||
if(p.complete())
|
if(p.complete())
|
||||||
break;
|
break;
|
||||||
bin_.commit(stream_.read_some(
|
bin_.commit(stream_.read_some(
|
||||||
|
|||||||
@@ -30,8 +30,6 @@
|
|||||||
// Include this to get all the basic includes included, to prevent errors
|
// Include this to get all the basic includes included, to prevent errors
|
||||||
#include <ripple/beast/core/core.unity.cpp>
|
#include <ripple/beast/core/core.unity.cpp>
|
||||||
|
|
||||||
#include <beast/http/HTTP.unity.cpp>
|
|
||||||
|
|
||||||
#include <beast/unit_test/define_print.cpp>
|
#include <beast/unit_test/define_print.cpp>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -543,13 +543,13 @@ public:
|
|||||||
streambuf sb;
|
streambuf sb;
|
||||||
read_until(s_, sb, "\r\n\r\n");
|
read_until(s_, sb, "\r\n\r\n");
|
||||||
using namespace beast;
|
using namespace beast;
|
||||||
http::body b;
|
deprecated_http::body b;
|
||||||
http::message m;
|
deprecated_http::message m;
|
||||||
http::parser p(m, b, false);
|
deprecated_http::parser p(m, b, false);
|
||||||
auto const result = p.write(sb.data());
|
auto const used = p.write(sb.data(), ec);
|
||||||
if (result.first || ! p.complete())
|
if (ec || ! p.complete())
|
||||||
throw std::runtime_error(result.first.message());
|
throw std::runtime_error(ec.message());
|
||||||
sb.consume(result.second);
|
sb.consume(used);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write a text message
|
// write a text message
|
||||||
|
|||||||
Reference in New Issue
Block a user