mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-19 18:15:50 +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 Include="..\..\src\beast\beast\asio\buffers_adapter.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\asio\buffers_debug.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\asio\consuming_buffers.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\asio\handler_alloc.h">
|
||||
@@ -361,62 +363,88 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\hash\xxhasher.h">
|
||||
</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>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\body.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\chunk_encode.h">
|
||||
</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>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\HTTP.unity.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\impl\basic_parser.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<None Include="..\..\src\beast\beast\http\impl\basic_headers.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\beast\http\impl\basic_parser.ipp">
|
||||
</None>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.c">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\impl\joyent_parser.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\impl\joyent_parser.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\impl\method.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\impl\URL.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<None Include="..\..\src\beast\beast\http\impl\message.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\beast\http\impl\read.ipp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\beast\http\impl\write.ipp">
|
||||
</None>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\message.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\method.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\parser.h">
|
||||
</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>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\tests\chunked_encoder.test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\src\beast_http_nodejs_parser.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\tests\parser.test.cpp">
|
||||
<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 Include="..\..\src\beast\beast\http\src\nodejs_parser.h">
|
||||
</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 Include="..\..\src\beast\beast\is_call_possible.h">
|
||||
</ClInclude>
|
||||
@@ -454,6 +482,10 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\unity\beast_hash_unity.cpp">
|
||||
</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">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.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)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</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>
|
||||
<ClInclude Include="..\..\src\ripple\beast\net\IPAddressConversion.h">
|
||||
@@ -1738,10 +1774,16 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\beast\net\IPEndpoint.h">
|
||||
</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">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\beast\net\URL.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\beast\nudb.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\beast\nudb\api.h">
|
||||
|
||||
@@ -49,14 +49,20 @@
|
||||
<Filter Include="beast\http">
|
||||
<UniqueIdentifier>{7138D215-DA65-98D5-EF7D-C9896685201E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast\http\detail">
|
||||
<UniqueIdentifier>{3E84AA4C-CB48-99F0-EB35-5603FF633A51}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast\http\impl">
|
||||
<UniqueIdentifier>{932F732F-F09E-5C50-C8A1-D62342CCAA1F}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast\http\impl\http-parser">
|
||||
<UniqueIdentifier>{59E40DE8-464F-35ED-5F22-E7B52FDE3ECD}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast\http\tests">
|
||||
<UniqueIdentifier>{7FFB535D-F2F1-0B27-4C2F-28A6BAFDE4ED}</UniqueIdentifier>
|
||||
<Filter Include="beast\http\src">
|
||||
<UniqueIdentifier>{CCA07C08-BF91-95E2-4980-7D56A618C37E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast\http\src\test">
|
||||
<UniqueIdentifier>{5F7F2E0C-4CDE-B1E1-1668-E06768D6FFD3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast\streams">
|
||||
<UniqueIdentifier>{7944CEAB-F8F9-1E2B-CD03-B3D9F78B20E9}</UniqueIdentifier>
|
||||
@@ -552,6 +558,9 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\asio\buffers_adapter.h">
|
||||
<Filter>beast\asio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\asio\buffers_debug.h">
|
||||
<Filter>beast\asio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\asio\consuming_buffers.h">
|
||||
<Filter>beast\asio</Filter>
|
||||
</ClInclude>
|
||||
@@ -699,6 +708,12 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\hash\xxhasher.h">
|
||||
<Filter>beast\hash</Filter>
|
||||
</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">
|
||||
<Filter>beast\http</Filter>
|
||||
</ClInclude>
|
||||
@@ -708,33 +723,48 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\http\chunk_encode.h">
|
||||
<Filter>beast\http</Filter>
|
||||
</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">
|
||||
<Filter>beast\http</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\HTTP.unity.cpp">
|
||||
<Filter>beast\http</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\impl\basic_parser.cpp">
|
||||
<None Include="..\..\src\beast\beast\http\impl\basic_headers.ipp">
|
||||
<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">
|
||||
<Filter>beast\http\impl\http-parser</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\impl\http-parser\http_parser.h">
|
||||
<Filter>beast\http\impl\http-parser</Filter>
|
||||
</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>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\impl\joyent_parser.h">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\beast\http\impl\read.ipp">
|
||||
<Filter>beast\http\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\impl\method.cpp">
|
||||
</None>
|
||||
<None Include="..\..\src\beast\beast\http\impl\write.ipp">
|
||||
<Filter>beast\http\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\impl\URL.cpp">
|
||||
<Filter>beast\http\impl</Filter>
|
||||
</ClCompile>
|
||||
</None>
|
||||
<ClInclude Include="..\..\src\beast\beast\http\message.h">
|
||||
<Filter>beast\http</Filter>
|
||||
</ClInclude>
|
||||
@@ -744,28 +774,46 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\http\parser.h">
|
||||
<Filter>beast\http</Filter>
|
||||
</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">
|
||||
<Filter>beast\http</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\tests\chunked_encoder.test.cpp">
|
||||
<Filter>beast\http\tests</Filter>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\src\beast_http_nodejs_parser.cpp">
|
||||
<Filter>beast\http\src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\http\tests\parser.test.cpp">
|
||||
<Filter>beast\http\tests</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 Include="..\..\src\beast\beast\http\src\nodejs_parser.h">
|
||||
<Filter>beast\http\src</Filter>
|
||||
</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>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\is_call_possible.h">
|
||||
@@ -807,6 +855,9 @@
|
||||
<ClCompile Include="..\..\src\beast\beast\unity\beast_hash_unity.cpp">
|
||||
<Filter>beast\unity</Filter>
|
||||
</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">
|
||||
<Filter>beast\unity</Filter>
|
||||
</ClCompile>
|
||||
@@ -2211,6 +2262,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\beast\net\impl\IPEndpoint.cpp">
|
||||
<Filter>ripple\beast\net\impl</Filter>
|
||||
</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">
|
||||
<Filter>ripple\beast\net</Filter>
|
||||
</ClInclude>
|
||||
@@ -2226,9 +2280,15 @@
|
||||
<ClInclude Include="..\..\src\ripple\beast\net\IPEndpoint.h">
|
||||
<Filter>ripple\beast\net</Filter>
|
||||
</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">
|
||||
<Filter>ripple\beast\net\tests</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\beast\net\URL.h">
|
||||
<Filter>ripple\beast\net</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\beast\nudb.h">
|
||||
<Filter>ripple\beast</Filter>
|
||||
</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/clock', '.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/test', '.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_clock_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_test_unity.cpp',
|
||||
'src/ripple/beast/unity/beast_container_unity.cpp',
|
||||
|
||||
@@ -41,6 +41,10 @@ project beast
|
||||
<include>.
|
||||
#<use>/boost//headers
|
||||
<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
|
||||
<threading>multi
|
||||
<link>static
|
||||
@@ -61,6 +65,8 @@ project beast
|
||||
<os>HPUX:<library>ipv6
|
||||
<os>QNXNTO:<library>socket
|
||||
<os>HAIKU:<library>network
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||
: usage-requirements
|
||||
<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
|
||||
#define BEAST_UTILITY_CI_CHAR_TRAITS_H_INCLUDED
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <cctype>
|
||||
@@ -34,16 +35,15 @@ struct ci_less
|
||||
{
|
||||
static bool const is_transparent = true;
|
||||
|
||||
template <class String>
|
||||
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::end;
|
||||
using char_type = typename String::value_type;
|
||||
return std::lexicographical_compare (
|
||||
return std::lexicographical_compare(
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#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/system/error_code.hpp>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <beast/cxx17/type_traits.h> // <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace joyent {
|
||||
struct http_parser;
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
private:
|
||||
// These structures must exactly match the
|
||||
// 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)];
|
||||
|
||||
http_parser state_;
|
||||
boost::system::error_code* ec_;
|
||||
bool complete_ = false;
|
||||
std::string url_;
|
||||
std::string status_;
|
||||
@@ -90,20 +108,36 @@ private:
|
||||
public:
|
||||
using error_code = boost::system::error_code;
|
||||
|
||||
virtual
|
||||
~basic_parser() = default;
|
||||
/** Move constructor.
|
||||
|
||||
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.
|
||||
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
|
||||
basic_parser (bool request) noexcept;
|
||||
|
||||
basic_parser&
|
||||
operator= (basic_parser&& other);
|
||||
basic_parser(bool request) noexcept;
|
||||
|
||||
/** Returns `true` if parsing is complete.
|
||||
|
||||
This is only defined when no errors have been returned.
|
||||
*/
|
||||
bool
|
||||
@@ -113,153 +147,406 @@ public:
|
||||
}
|
||||
|
||||
/** 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.
|
||||
The return value includes the error code if any,
|
||||
and the number of bytes consumed in the input sequence.
|
||||
@param buffers The buffers to write. These must meet the
|
||||
requirements of ConstBufferSequence.
|
||||
@return A pair with bool success, and the number of bytes consumed.
|
||||
@param data A pointer to a buffer representing the input sequence.
|
||||
@param size The number of bytes in the buffer pointed to by data.
|
||||
|
||||
@throws boost::system::system_error Thrown on failure.
|
||||
|
||||
@return The number of bytes consumed in the input sequence.
|
||||
*/
|
||||
template <class ConstBufferSequence>
|
||||
std::pair <error_code, std::size_t>
|
||||
write (ConstBufferSequence const& buffers);
|
||||
std::size_t
|
||||
write(void const* data, std::size_t size)
|
||||
{
|
||||
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.
|
||||
|
||||
HTTP needs to know where the end of the stream is. For example,
|
||||
sometimes servers send responses without Content-Length and
|
||||
expect the client to consume input (for the body) until EOF.
|
||||
Callbacks and errors will still be processed as usual.
|
||||
|
||||
@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
|
||||
on_start() = 0;
|
||||
write_eof()
|
||||
{
|
||||
error_code ec;
|
||||
write_eof(ec);
|
||||
if(ec)
|
||||
throw boost::system::system_error{ec};
|
||||
}
|
||||
|
||||
/** Called for each header field. */
|
||||
virtual
|
||||
void
|
||||
on_field (std::string const& field, std::string const& value) = 0;
|
||||
/** Called to indicate the end of file.
|
||||
|
||||
/** 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.
|
||||
When upgrade is true, no content-body is expected, and the
|
||||
return value is ignored.
|
||||
HTTP needs to know where the end of the stream is. For example,
|
||||
sometimes servers send responses without Content-Length and
|
||||
expect the client to consume input (for the body) until EOF.
|
||||
Callbacks and errors will still be processed as usual.
|
||||
|
||||
@param method The HTTP method specified in the request line
|
||||
@param major The HTTP major version number
|
||||
@param minor The HTTP minor version number
|
||||
@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.
|
||||
@note This is typically called when a socket read returns eof.
|
||||
|
||||
@param ec Set to the error, if any error occurred.
|
||||
*/
|
||||
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
|
||||
on_body (void const* data, std::size_t bytes) = 0;
|
||||
|
||||
/** Called once when the message is complete. */
|
||||
virtual
|
||||
void
|
||||
on_complete() = 0;
|
||||
write_eof(error_code& ec);
|
||||
|
||||
private:
|
||||
void check_header();
|
||||
Derived&
|
||||
impl()
|
||||
{
|
||||
return *static_cast<Derived*>(this);
|
||||
}
|
||||
|
||||
int do_message_start ();
|
||||
int do_url (char const* in, std::size_t bytes);
|
||||
int do_status (char const* in, std::size_t bytes);
|
||||
int do_header_field (char const* in, std::size_t bytes);
|
||||
int do_header_value (char const* in, std::size_t bytes);
|
||||
int do_headers_complete ();
|
||||
int do_body (char const* in, std::size_t bytes);
|
||||
int do_message_complete ();
|
||||
int do_chunk_header();
|
||||
int do_chunk_complete();
|
||||
template<class C>
|
||||
class has_on_start_t
|
||||
{
|
||||
template<class T, class R =
|
||||
decltype(std::declval<T>().on_start(), std::true_type{})>
|
||||
static R check(int);
|
||||
template <class>
|
||||
static std::false_type check(...);
|
||||
using type = decltype(check<C>(0));
|
||||
public:
|
||||
static bool const value = type::value;
|
||||
};
|
||||
template<class C>
|
||||
using has_on_start =
|
||||
std::bool_constant<has_on_start_t<C>::value>;
|
||||
|
||||
static int cb_message_start (joyent::http_parser*);
|
||||
static int cb_url (joyent::http_parser*, char const*, std::size_t);
|
||||
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);
|
||||
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);
|
||||
static int cb_message_complete (joyent::http_parser*);
|
||||
static int cb_chunk_header (joyent::http_parser*);
|
||||
static int cb_chunk_complete (joyent::http_parser*);
|
||||
void
|
||||
call_on_start(std::true_type)
|
||||
{
|
||||
impl().on_start();
|
||||
}
|
||||
|
||||
void
|
||||
call_on_start(std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
template<class C>
|
||||
class has_on_field_t
|
||||
{
|
||||
template<class T, class R =
|
||||
decltype(std::declval<T>().on_field(
|
||||
std::declval<std::string const&>(),
|
||||
std::declval<std::string const&>()),
|
||||
std::true_type{})>
|
||||
static R check(int);
|
||||
template <class>
|
||||
static std::false_type check(...);
|
||||
using type = decltype(check<C>(0));
|
||||
public:
|
||||
static bool const value = type::value;
|
||||
};
|
||||
template<class C>
|
||||
using has_on_field =
|
||||
std::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>
|
||||
auto
|
||||
basic_parser::write (ConstBufferSequence const& buffers) ->
|
||||
std::pair <error_code, std::size_t>
|
||||
template<class Derived>
|
||||
template<class ConstBufferSequence>
|
||||
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)
|
||||
{
|
||||
std::size_t bytes_consumed;
|
||||
std::tie (result.first, bytes_consumed) =
|
||||
write (boost::asio::buffer_cast <void const*> (buffer),
|
||||
boost::asio::buffer_size (buffer));
|
||||
if (result.first)
|
||||
break;
|
||||
result.second += bytes_consumed;
|
||||
if (complete())
|
||||
auto const n = write(
|
||||
buffer_cast<void const*>(buffer),
|
||||
buffer_size(buffer), ec);
|
||||
if(ec)
|
||||
return 0;
|
||||
bytes_used += n;
|
||||
if(complete())
|
||||
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
|
||||
} // beast
|
||||
|
||||
#include <beast/http/impl/basic_parser.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace deprecated_http {
|
||||
|
||||
/** Container for the HTTP content-body. */
|
||||
class body
|
||||
@@ -144,7 +144,7 @@ body::data() const
|
||||
return buf_->data();
|
||||
}
|
||||
|
||||
} // http
|
||||
} // deprecated_http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -148,8 +148,8 @@ chunk_encoded_buffers<Buffers>::to_hex(
|
||||
|
||||
template <class Buffers>
|
||||
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&
|
||||
{
|
||||
assert(buffers_);
|
||||
assert(where_ != Where::begin);
|
||||
assert(where_ != Where::head);
|
||||
if (where_ == Where::end)
|
||||
where_ = Where::input;
|
||||
else if (iter_ != buffers_->buffers_.begin())
|
||||
@@ -247,37 +247,44 @@ chunk_encoded_buffers<Buffers>::const_iterator::const_iterator(
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
} // detail
|
||||
|
||||
/** Returns a chunk-encoded BufferSequence.
|
||||
|
||||
See:
|
||||
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 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 Buffers>
|
||||
detail::chunk_encoded_buffers<Buffers>
|
||||
chunk_encode (Buffers const& buffers,
|
||||
template<class ConstBufferSequence>
|
||||
#if GENERATING_DOCS
|
||||
implementation_defined
|
||||
#else
|
||||
detail::chunk_encoded_buffers<ConstBufferSequence>
|
||||
#endif
|
||||
chunk_encode(ConstBufferSequence const& buffers,
|
||||
bool final_chunk = false)
|
||||
{
|
||||
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
|
||||
#if GENERATING_DOCS
|
||||
implementation_defined
|
||||
#else
|
||||
boost::asio::const_buffers_1
|
||||
#endif
|
||||
chunk_encode_final()
|
||||
{
|
||||
return boost::asio::const_buffers_1(
|
||||
"0\r\n\r\n", 5);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
} // http
|
||||
} // 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
|
||||
#include <BeastConfig.h>
|
||||
#ifndef BEAST_HTTP_ERROR_H_INCLUDED
|
||||
#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
|
||||
|
||||
#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
|
||||
#define BEAST_HTTP_HEADERS_H_INCLUDED
|
||||
|
||||
#include <beast/ci_char_traits.h>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <beast/http/basic_headers.h>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** Holds a collection of HTTP headers. */
|
||||
class headers
|
||||
{
|
||||
public:
|
||||
using value_type = std::pair<std::string, std::string>;
|
||||
template<class Allocator>
|
||||
using headers = basic_headers<Allocator>;
|
||||
|
||||
private:
|
||||
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>>
|
||||
{
|
||||
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;
|
||||
}
|
||||
using http_headers =
|
||||
basic_headers<std::allocator<char>>;
|
||||
|
||||
} // http
|
||||
} // 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
|
||||
#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/headers.h>
|
||||
#include <beast/ci_char_traits.h>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
#include <beast/http/detail/writes.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <ostream>
|
||||
@@ -34,7 +193,7 @@
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace deprecated_http {
|
||||
|
||||
inline
|
||||
std::pair<int, int>
|
||||
@@ -70,17 +229,16 @@ private:
|
||||
|
||||
public:
|
||||
~message() = default;
|
||||
message (message const&) = delete;
|
||||
message& operator= (message const&) = delete;
|
||||
message (message const&) = default;
|
||||
message (message&& other) = default;
|
||||
message& operator= (message const&) = default;
|
||||
message& operator= (message&& other) = default;
|
||||
|
||||
template <class = void>
|
||||
message();
|
||||
|
||||
message (message&& other) = default;
|
||||
message& operator= (message&& other) = default;
|
||||
|
||||
// Memberspace
|
||||
beast::http::headers headers;
|
||||
beast::http::headers<std::allocator<char>> headers;
|
||||
|
||||
bool
|
||||
request() const
|
||||
@@ -221,49 +379,31 @@ write (Streambuf& stream, message const& m)
|
||||
{
|
||||
if (m.request())
|
||||
{
|
||||
write (stream, to_string(m.method()));
|
||||
write (stream, " ");
|
||||
write (stream, m.url());
|
||||
write (stream, " HTTP/");
|
||||
write (stream, std::to_string(m.version().first));
|
||||
write (stream, ".");
|
||||
write (stream, std::to_string(m.version().second));
|
||||
http::detail::write (stream, to_string(m.method()));
|
||||
http::detail::write (stream, " ");
|
||||
http::detail::write (stream, m.url());
|
||||
http::detail::write (stream, " HTTP/");
|
||||
http::detail::write (stream, std::to_string(m.version().first));
|
||||
http::detail::write (stream, ".");
|
||||
http::detail::write (stream, std::to_string(m.version().second));
|
||||
}
|
||||
else
|
||||
{
|
||||
write (stream, "HTTP/");
|
||||
write (stream, std::to_string(m.version().first));
|
||||
write (stream, ".");
|
||||
write (stream, std::to_string(m.version().second));
|
||||
write (stream, " ");
|
||||
write (stream, std::to_string(m.status()));
|
||||
write (stream, " ");
|
||||
write (stream, m.reason());
|
||||
http::detail::write (stream, "HTTP/");
|
||||
http::detail::write (stream, std::to_string(m.version().first));
|
||||
http::detail::write (stream, ".");
|
||||
http::detail::write (stream, std::to_string(m.version().second));
|
||||
http::detail::write (stream, " ");
|
||||
http::detail::write (stream, std::to_string(m.status()));
|
||||
http::detail::write (stream, " ");
|
||||
http::detail::write (stream, m.reason());
|
||||
}
|
||||
write (stream, "\r\n");
|
||||
write(stream, m.headers);
|
||||
write (stream, "\r\n");
|
||||
http::detail::write (stream, "\r\n");
|
||||
write_fields(stream, m.headers);
|
||||
http::detail::write (stream, "\r\n");
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
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
|
||||
} // deprecated_http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -78,8 +78,51 @@ enum class method_t
|
||||
http_unlink
|
||||
};
|
||||
|
||||
template<class = void>
|
||||
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>
|
||||
Stream&
|
||||
@@ -89,10 +132,60 @@ operator<< (Stream& s, method_t m)
|
||||
}
|
||||
|
||||
/** Returns the string corresponding to the numeric HTTP status code. */
|
||||
template<class = void>
|
||||
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
|
||||
|
||||
@@ -20,6 +20,157 @@
|
||||
#ifndef 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/body.h>
|
||||
#include <functional>
|
||||
@@ -27,167 +178,105 @@
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace deprecated_http {
|
||||
|
||||
/** Parser for HTTP messages.
|
||||
The result is stored in a message object.
|
||||
*/
|
||||
class parser : public beast::http::basic_parser
|
||||
class parser
|
||||
: public beast::http::basic_parser<parser>
|
||||
{
|
||||
private:
|
||||
std::reference_wrapper <message> message_;
|
||||
// friend class basic_parser<parser>;
|
||||
|
||||
message& m_;
|
||||
std::function<void(void const*, std::size_t)> write_body_;
|
||||
|
||||
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.
|
||||
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 write_body function. Transfer encodings are applied before
|
||||
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)
|
||||
: beast::http::basic_parser (request)
|
||||
, message_(m)
|
||||
: basic_parser(request)
|
||||
, m_(m)
|
||||
, write_body_(std::move(write_body))
|
||||
{
|
||||
message_.get().request(request);
|
||||
m_.request(request);
|
||||
}
|
||||
|
||||
parser (message& m, body& b, bool request)
|
||||
: beast::http::basic_parser (request)
|
||||
, message_(m)
|
||||
parser(message& m, body& b, bool request)
|
||||
: basic_parser(request)
|
||||
, m_(m)
|
||||
{
|
||||
write_body_ = [&b](void const* data, std::size_t size)
|
||||
{
|
||||
b.write(data, size);
|
||||
};
|
||||
|
||||
message_.get().request(request);
|
||||
m_.request(request);
|
||||
}
|
||||
|
||||
parser& operator= (parser&& other) = default;
|
||||
|
||||
private:
|
||||
template <class = void>
|
||||
//private:
|
||||
void
|
||||
do_start ();
|
||||
|
||||
template <class = void>
|
||||
bool
|
||||
do_request (method_t method, std::string const& url,
|
||||
int major, int minor, bool keep_alive, bool upgrade);
|
||||
|
||||
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
|
||||
on_start()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_headers_complete(error_code&)
|
||||
{
|
||||
do_start();
|
||||
}
|
||||
|
||||
bool
|
||||
on_request (method_t method, std::string const& url,
|
||||
int major, int minor, bool keep_alive, bool upgrade) override
|
||||
on_request(http::method_t method, std::string const& url,
|
||||
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
|
||||
on_response (int status, std::string const& text,
|
||||
int major, int minor, bool keep_alive, bool upgrade) override
|
||||
on_response(int status, std::string const& text,
|
||||
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
|
||||
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
|
||||
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
|
||||
on_complete() override
|
||||
on_complete()
|
||||
{
|
||||
do_complete();
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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
|
||||
} // deprecated_http
|
||||
} // beast
|
||||
|
||||
#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
|
||||
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
|
||||
purpose with or without fee is hereby granted: provided that the above
|
||||
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
|
||||
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/method.h>
|
||||
#include <cassert>
|
||||
#ifndef BEAST_HTTP_REASON_H_INCLUDED
|
||||
#define BEAST_HTTP_REASON_H_INCLUDED
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
std::string
|
||||
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";
|
||||
}
|
||||
|
||||
std::string
|
||||
status_text (int status)
|
||||
/** Returns the text for a known status code integer. */
|
||||
template<class = void>
|
||||
char const*
|
||||
reason_string(int status)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
@@ -88,7 +45,6 @@ status_text (int status)
|
||||
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";
|
||||
@@ -114,11 +70,15 @@ status_text (int status)
|
||||
case 503: return "Service Unavailable";
|
||||
case 504: return "Gateway Timeout";
|
||||
case 505: return "HTTP Version Not Supported";
|
||||
|
||||
case 306: return "<reserved>";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown HTTP status";
|
||||
return "<unknown-status>";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -17,47 +17,30 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_HTTP_DETAIL_HEADER_TRAITS_H_INCLUDED
|
||||
#define BEAST_HTTP_DETAIL_HEADER_TRAITS_H_INCLUDED
|
||||
#ifndef BEAST_HTTP_RESUME_CONTEXT_H_INCLUDED
|
||||
#define BEAST_HTTP_RESUME_CONTEXT_H_INCLUDED
|
||||
|
||||
#include <beast/utility/ci_char_traits.h>
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
// Utilities for dealing with HTTP headers
|
||||
/** A functor that resumes a write operation.
|
||||
|
||||
template <class Allocator = std::allocator <char>>
|
||||
using basic_field_string =
|
||||
std::basic_string <char, ci_char_traits, Allocator>;
|
||||
An rvalue reference to an object of this type is provided by the
|
||||
write implementation to the `writer` associated with the body of
|
||||
a message being sent.
|
||||
|
||||
using field_string = basic_field_string <>;
|
||||
|
||||
using field_string_ref = boost::basic_string_ref <char, ci_char_traits>;
|
||||
|
||||
/** Returns `true` if two header fields are the same.
|
||||
The comparison is case-insensitive.
|
||||
If it is desired that the `writer` suspend the write operation (for
|
||||
example, to wait until data is ready), it can take ownership of
|
||||
the resume context using a move. Then, it returns `boost::indeterminate`
|
||||
to indicate that the write operation should suspend. Later, the calling
|
||||
code invokes the resume function and the write operation continues
|
||||
from where it left off.
|
||||
*/
|
||||
template <class Alloc1, class Alloc2>
|
||||
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());
|
||||
}
|
||||
using resume_context = std::function<void(void)>;
|
||||
|
||||
/** Returns the string with leading and trailing LWS removed. */
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -20,10 +20,14 @@
|
||||
#ifndef 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 <cctype>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <tuple> // for std::tie, remove ASAP
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -36,20 +40,34 @@ namespace beast {
|
||||
*/
|
||||
namespace rfc2616 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct ci_equal_pred
|
||||
{
|
||||
bool operator()(char c1, char c2)
|
||||
{
|
||||
// VFALCO TODO Use a table lookup here
|
||||
return std::tolower(c1) == std::tolower(c2);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
/** Returns `true` if `c` is linear white space.
|
||||
|
||||
This excludes the CRLF sequence allowed for line continuations.
|
||||
*/
|
||||
template <class CharT>
|
||||
inline
|
||||
bool
|
||||
is_lws (CharT c)
|
||||
is_lws(char c)
|
||||
{
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is any whitespace character. */
|
||||
template <class CharT>
|
||||
inline
|
||||
bool
|
||||
is_white (CharT c)
|
||||
is_white(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -61,18 +79,19 @@ is_white (CharT c)
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is a control character. */
|
||||
template <class CharT>
|
||||
inline
|
||||
bool
|
||||
is_ctl (CharT c)
|
||||
is_control(char c)
|
||||
{
|
||||
return c <= 31 || c >= 127;
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is a separator. */
|
||||
template <class CharT>
|
||||
inline
|
||||
bool
|
||||
is_sep (CharT c)
|
||||
is_separator(char c)
|
||||
{
|
||||
// VFALCO Could use a static table
|
||||
switch (c)
|
||||
{
|
||||
case '(': case ')': case '<': case '>': case '@':
|
||||
@@ -83,12 +102,20 @@ is_sep (CharT c)
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is a character. */
|
||||
inline
|
||||
bool
|
||||
is_char(char c)
|
||||
{
|
||||
return c >= 0 && c <= 127;
|
||||
}
|
||||
|
||||
template <class FwdIter>
|
||||
FwdIter
|
||||
trim_left (FwdIter first, FwdIter last)
|
||||
{
|
||||
return std::find_if_not (first, last,
|
||||
&is_white <typename FwdIter::value_type>);
|
||||
is_white);
|
||||
}
|
||||
|
||||
template <class FwdIter>
|
||||
@@ -166,8 +193,9 @@ trim (std::string const& s)
|
||||
*/
|
||||
template <class FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename FwdIt::value_type>>,
|
||||
class Char>
|
||||
std::basic_string<typename
|
||||
std::iterator_traits<FwdIt>::value_type>>,
|
||||
class Char>
|
||||
Result
|
||||
split(FwdIt first, FwdIt last, Char delim)
|
||||
{
|
||||
@@ -239,7 +267,8 @@ split(FwdIt first, FwdIt last, Char delim)
|
||||
|
||||
template <class FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename FwdIt::value_type>>>
|
||||
std::basic_string<typename std::iterator_traits<
|
||||
FwdIt>::value_type>>>
|
||||
Result
|
||||
split_commas(FwdIt first, FwdIt last)
|
||||
{
|
||||
@@ -248,11 +277,194 @@ split_commas(FwdIt first, FwdIt last)
|
||||
|
||||
template <class Result = std::vector<std::string>>
|
||||
Result
|
||||
split_commas(std::string const& s)
|
||||
split_commas(boost::string_ref const& s)
|
||||
{
|
||||
return split_commas(s.begin(), s.end());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Iterates through a comma separated list.
|
||||
|
||||
Meets the requirements of ForwardIterator.
|
||||
|
||||
List defined in rfc2616 2.1.
|
||||
|
||||
@note Values returned may contain backslash escapes.
|
||||
*/
|
||||
class list_iterator
|
||||
{
|
||||
using iter_type = boost::string_ref::const_iterator;
|
||||
|
||||
iter_type it_;
|
||||
iter_type end_;
|
||||
boost::string_ref value_;
|
||||
|
||||
public:
|
||||
using value_type = boost::string_ref;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type const&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category =
|
||||
std::forward_iterator_tag;
|
||||
|
||||
list_iterator(iter_type begin, iter_type end)
|
||||
: it_(begin)
|
||||
, end_(end)
|
||||
{
|
||||
if(it_ != end_)
|
||||
increment();
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(list_iterator const& other) const
|
||||
{
|
||||
return other.it_ == it_ && other.end_ == end_
|
||||
&& other.value_.size() == value_.size();
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(list_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &*(*this);
|
||||
}
|
||||
|
||||
list_iterator&
|
||||
operator++()
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
list_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
template<class = void>
|
||||
void
|
||||
increment();
|
||||
};
|
||||
|
||||
template<class>
|
||||
void
|
||||
list_iterator::increment()
|
||||
{
|
||||
value_.clear();
|
||||
while(it_ != end_)
|
||||
{
|
||||
if(*it_ == '"')
|
||||
{
|
||||
// quoted-string
|
||||
++it_;
|
||||
if(it_ == end_)
|
||||
return;
|
||||
if(*it_ != '"')
|
||||
{
|
||||
auto start = it_;
|
||||
for(;;)
|
||||
{
|
||||
++it_;
|
||||
if(it_ == end_)
|
||||
{
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
return;
|
||||
}
|
||||
if(*it_ == '"')
|
||||
{
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
++it_;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
++it_;
|
||||
}
|
||||
else if(*it_ == ',')
|
||||
{
|
||||
it_++;
|
||||
continue;
|
||||
}
|
||||
else if(is_lws(*it_))
|
||||
{
|
||||
++it_;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto start = it_;
|
||||
for(;;)
|
||||
{
|
||||
++it_;
|
||||
if(it_ == end_ ||
|
||||
*it_ == ',' ||
|
||||
is_lws(*it_))
|
||||
{
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if two strings are equal.
|
||||
|
||||
A case-insensitive comparison is used.
|
||||
*/
|
||||
inline
|
||||
bool
|
||||
ci_equal(boost::string_ref s1, boost::string_ref s2)
|
||||
{
|
||||
return boost::range::equal(s1, s2,
|
||||
detail::ci_equal_pred{});
|
||||
}
|
||||
|
||||
/** Returns a range representing the list. */
|
||||
inline
|
||||
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
|
||||
|
||||
} // 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 <boost/system/error_code.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace joyent {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4127) // conditional expression is constant
|
||||
@@ -34,33 +31,10 @@ namespace joyent {
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
beast::http::method_t
|
||||
convert_http_method(http_method m)
|
||||
{
|
||||
using namespace beast;
|
||||
switch (m)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
#define BEAST_HTTP_JOYENT_PARSER_H_INCLUDED
|
||||
#ifndef BEAST_HTTP_NODEJS_PARSER_H_INCLUDED
|
||||
#define BEAST_HTTP_NODEJS_PARSER_H_INCLUDED
|
||||
|
||||
#include <beast/http/method.h>
|
||||
|
||||
// TODO Use <system_error>
|
||||
#include <beast/http/impl/http-parser/http_parser.h>
|
||||
#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 joyent {
|
||||
|
||||
#include <beast/http/impl/http-parser/http_parser.h>
|
||||
|
||||
http::method_t
|
||||
convert_http_method (joyent::http_method m);
|
||||
|
||||
boost::system::error_code
|
||||
convert_http_errno (joyent::http_errno err);
|
||||
|
||||
}
|
||||
}
|
||||
namespace boost {
|
||||
namespace system {
|
||||
template<>
|
||||
struct is_error_code_enum<http_errno>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
template<>
|
||||
struct is_error_condition_enum<http_errno>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
} // system
|
||||
} // boost
|
||||
|
||||
#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>
|
||||
|
||||
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:
|
||||
std::pair <message, bool>
|
||||
request (std::string const& text)
|
||||
message
|
||||
request(std::string const& text)
|
||||
{
|
||||
message m;
|
||||
body b;
|
||||
parser p (m, b, true);
|
||||
auto result (p.write (boost::asio::buffer(text)));
|
||||
message m;
|
||||
parser p(m, b, true);
|
||||
auto const used =
|
||||
p.write(boost::asio::buffer(text));
|
||||
expect(used == text.size());
|
||||
p.write_eof();
|
||||
return std::make_pair (std::move(m), result.first);
|
||||
}
|
||||
|
||||
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"] << "|";
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
test_headers()
|
||||
{
|
||||
headers h;
|
||||
h.append("Field", "Value");
|
||||
beast::http::headers<std::allocator<char>> h;
|
||||
h.insert("Field", "Value");
|
||||
expect (h.erase("Field") == 1);
|
||||
}
|
||||
|
||||
@@ -76,14 +60,14 @@ public:
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"\r\n"
|
||||
;
|
||||
message m;
|
||||
body b;
|
||||
message m;
|
||||
parser p (m, b, true);
|
||||
auto result (p.write (boost::asio::buffer(text)));
|
||||
expect (! result.first);
|
||||
auto result2 (p.write_eof());
|
||||
expect (! result2);
|
||||
expect (p.complete());
|
||||
auto const used = p.write(
|
||||
boost::asio::buffer(text));
|
||||
expect(used == text.size());
|
||||
p.write_eof();
|
||||
expect(p.complete());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -92,17 +76,19 @@ public:
|
||||
"GET\r\n"
|
||||
"\r\n"
|
||||
;
|
||||
message m;
|
||||
body b;
|
||||
parser p (m, b, true);
|
||||
auto result = p.write (boost::asio::buffer(text));
|
||||
if (expect (result.first))
|
||||
expect (result.first.message() == "invalid HTTP method");
|
||||
message m;
|
||||
parser p(m, b, true);
|
||||
boost::system::error_code ec;
|
||||
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
|
||||
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>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
#include "urls_large_data.h"
|
||||
|
||||
// Data from Alexa top 1 million sites
|
||||
// http://s3.amazonaws.com/alexa-static/top-1m.csv.zip
|
||||
//
|
||||
std::vector <char const*> const&
|
||||
std::vector<char const*> const&
|
||||
urls_large_data()
|
||||
{
|
||||
static std::vector <char const*> const urls ({
|
||||
@@ -10032,7 +10029,3 @@ urls_large_data()
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,12 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_HTTP_URLS_LARGE_DATA_H_INCLUDED
|
||||
#define BEAST_HTTP_URLS_LARGE_DATA_H_INCLUDED
|
||||
#ifndef URLS_LARGE_DATA_H_INCLUDED
|
||||
#define URLS_LARGE_DATA_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
std::vector <char const*> const&
|
||||
std::vector<char const*> const&
|
||||
urls_large_data();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -14,6 +14,7 @@ unit-test all :
|
||||
asio.cpp
|
||||
async_completion.cpp
|
||||
basic_streambuf.cpp
|
||||
../basic_headers.cpp
|
||||
bind_handler.cpp
|
||||
buffers_adapter.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 {
|
||||
|
||||
@@ -104,9 +105,9 @@ parse_URL(std::string const& url)
|
||||
std::size_t const buflen (url.size ());
|
||||
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{});
|
||||
|
||||
std::string scheme;
|
||||
@@ -118,54 +119,54 @@ parse_URL(std::string const& url)
|
||||
std::string fragment;
|
||||
std::string userinfo;
|
||||
|
||||
if ((parser.field_set & (1<<joyent::UF_SCHEMA)) != 0)
|
||||
if ((parser.field_set & (1<<UF_SCHEMA)) != 0)
|
||||
{
|
||||
scheme = std::string (
|
||||
buf + parser.field_data [joyent::UF_SCHEMA].off,
|
||||
parser.field_data [joyent::UF_SCHEMA].len);
|
||||
buf + parser.field_data [UF_SCHEMA].off,
|
||||
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 (
|
||||
buf + parser.field_data [joyent::UF_HOST].off,
|
||||
parser.field_data [joyent::UF_HOST].len);
|
||||
buf + parser.field_data [UF_HOST].off,
|
||||
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_string = std::string (
|
||||
buf + parser.field_data [joyent::UF_PORT].off,
|
||||
parser.field_data [joyent::UF_PORT].len);
|
||||
buf + parser.field_data [UF_PORT].off,
|
||||
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 (
|
||||
buf + parser.field_data [joyent::UF_PATH].off,
|
||||
parser.field_data [joyent::UF_PATH].len);
|
||||
buf + parser.field_data [UF_PATH].off,
|
||||
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 (
|
||||
buf + parser.field_data [joyent::UF_QUERY].off,
|
||||
parser.field_data [joyent::UF_QUERY].len);
|
||||
buf + parser.field_data [UF_QUERY].off,
|
||||
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 (
|
||||
buf + parser.field_data [joyent::UF_FRAGMENT].off,
|
||||
parser.field_data [joyent::UF_FRAGMENT].len);
|
||||
buf + parser.field_data [UF_FRAGMENT].off,
|
||||
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 (
|
||||
buf + parser.field_data [joyent::UF_USERINFO].off,
|
||||
parser.field_data [joyent::UF_USERINFO].len);
|
||||
buf + parser.field_data [UF_USERINFO].off,
|
||||
parser.field_data [UF_USERINFO].len);
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
namespace beast {
|
||||
@@ -21,4 +21,7 @@
|
||||
#include <ripple/beast/net/impl/IPAddressV6.cpp>
|
||||
#include <ripple/beast/net/impl/IPEndpoint.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>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <ripple/protocol/PublicKey.h> // NIKB Breaks levelization (TEMP)
|
||||
#include <ripple/protocol/SecretKey.h> // NIKB Breaks levelization (TEMP)
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <beast/http/URL.h>
|
||||
#include <ripple/beast/net/URL.h>
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <beast/ci_char_traits.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/SystemParameters.h>
|
||||
#include <ripple/net/HTTPClient.h>
|
||||
#include <beast/http/URL.h>
|
||||
#include <ripple/beast/net/URL.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
#include <beast/streams/debug_ostream.h>
|
||||
#include <beast/ci_char_traits.h>
|
||||
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
virtual
|
||||
Handoff
|
||||
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;
|
||||
|
||||
/** Establish a peer connection to the specified endpoint.
|
||||
|
||||
@@ -218,7 +218,7 @@ ConnectAttempt::onHandshake (error_code ec)
|
||||
if (! sharedValue)
|
||||
return close(); // makeSharedValue logs
|
||||
|
||||
beast::http::message req = makeRequest(
|
||||
beast::deprecated_http::message req = makeRequest(
|
||||
! overlay_.peerFinder().config().peerPrivate,
|
||||
remote_endpoint_.address());
|
||||
auto const hello = buildHello (
|
||||
@@ -226,10 +226,9 @@ ConnectAttempt::onHandshake (error_code ec)
|
||||
overlay_.setup().public_ip,
|
||||
beast::IPAddressConversion::from_asio(remote_endpoint_),
|
||||
app_);
|
||||
appendHello (req, hello);
|
||||
appendHello (req.headers, hello);
|
||||
|
||||
using beast::http::write;
|
||||
write (write_buf_, req);
|
||||
beast::deprecated_http::write (write_buf_, req);
|
||||
|
||||
setTimer();
|
||||
stream_.async_write_some (write_buf_.data(),
|
||||
@@ -293,10 +292,9 @@ ConnectAttempt::onRead (error_code ec, std::size_t bytes_transferred)
|
||||
|
||||
if (! ec)
|
||||
{
|
||||
write_buf_.commit (bytes_transferred);
|
||||
std::size_t bytes_consumed;
|
||||
std::tie (ec, bytes_consumed) = parser_.write(
|
||||
write_buf_.data());
|
||||
write_buf_.commit(bytes_transferred);
|
||||
auto bytes_consumed = parser_.write(
|
||||
write_buf_.data(), ec);
|
||||
if (! ec)
|
||||
{
|
||||
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,
|
||||
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.url ("/");
|
||||
m.version (1, 1);
|
||||
m.headers.append ("User-Agent", BuildInfo::getFullVersionString());
|
||||
m.headers.append ("Upgrade", "RTXP/1.2");
|
||||
m.headers.insert ("User-Agent", BuildInfo::getFullVersionString());
|
||||
m.headers.insert ("Upgrade", "RTXP/1.2");
|
||||
//std::string("RTXP/") + to_string (BuildInfo::getCurrentProtocol()));
|
||||
m.headers.append ("Connection", "Upgrade");
|
||||
m.headers.append ("Connect-As", "Peer");
|
||||
m.headers.append ("Crawl", crawl ? "public" : "private");
|
||||
m.headers.insert ("Connection", "Upgrade");
|
||||
m.headers.insert ("Connect-As", "Peer");
|
||||
m.headers.insert ("Crawl", crawl ? "public" : "private");
|
||||
return m;
|
||||
}
|
||||
|
||||
template <class Streambuf>
|
||||
void
|
||||
ConnectAttempt::processResponse (beast::http::message const& m,
|
||||
ConnectAttempt::processResponse (beast::deprecated_http::message const& m,
|
||||
Streambuf const& body)
|
||||
{
|
||||
if (response_.status() == 503)
|
||||
@@ -392,7 +390,7 @@ ConnectAttempt::processResponse (beast::http::message const& m,
|
||||
return close();
|
||||
}
|
||||
|
||||
auto hello = parseHello (response_, journal_);
|
||||
auto hello = parseHello (false, response_.headers, journal_);
|
||||
if(! hello)
|
||||
return fail("processResponse: Bad TMHello");
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ private:
|
||||
beast::asio::ssl_bundle::stream_type& stream_;
|
||||
beast::streambuf read_buf_;
|
||||
beast::streambuf write_buf_;
|
||||
beast::http::message response_;
|
||||
beast::deprecated_http::message response_;
|
||||
beast::streambuf body_;
|
||||
beast::http::parser parser_;
|
||||
beast::deprecated_http::parser parser_;
|
||||
PeerFinder::Slot::ptr slot_;
|
||||
|
||||
public:
|
||||
@@ -100,12 +100,12 @@ private:
|
||||
void onShutdown (error_code ec);
|
||||
|
||||
static
|
||||
beast::http::message
|
||||
beast::deprecated_http::message
|
||||
makeRequest (bool crawl,
|
||||
boost::asio::ip::address const& remote_address);
|
||||
|
||||
template <class Streambuf>
|
||||
void processResponse (beast::http::message const& m,
|
||||
void processResponse (beast::deprecated_http::message const& m,
|
||||
Streambuf const& body);
|
||||
|
||||
template <class = void>
|
||||
|
||||
@@ -171,7 +171,7 @@ OverlayImpl::~OverlayImpl ()
|
||||
|
||||
Handoff
|
||||
OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
endpoint_type remote_endpoint)
|
||||
{
|
||||
auto const id = next_id_++;
|
||||
@@ -226,14 +226,14 @@ OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
handoff.moved = false;
|
||||
handoff.response = makeRedirectResponse(slot, request,
|
||||
remote_endpoint.address());
|
||||
handoff.keep_alive = request.keep_alive();
|
||||
handoff.keep_alive = is_keep_alive(request);
|
||||
return handoff;
|
||||
}
|
||||
}
|
||||
|
||||
handoff.moved = true;
|
||||
|
||||
auto hello = parseHello (request, journal);
|
||||
auto hello = parseHello (true, request.headers, journal);
|
||||
if(! hello)
|
||||
return handoff;
|
||||
|
||||
@@ -260,7 +260,7 @@ OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
handoff.moved = false;
|
||||
handoff.response = makeRedirectResponse(slot, request,
|
||||
remote_endpoint.address());
|
||||
handoff.keep_alive = request.keep_alive();
|
||||
handoff.keep_alive = is_keep_alive(request);
|
||||
return handoff;
|
||||
}
|
||||
|
||||
@@ -289,7 +289,19 @@ OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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())
|
||||
return false;
|
||||
@@ -297,7 +309,7 @@ OverlayImpl::isPeerUpgrade(beast::http::message const& request)
|
||||
request.headers["Upgrade"]);
|
||||
if (versions.size() == 0)
|
||||
return false;
|
||||
if (! request.request() && request.status() != 101)
|
||||
if(! request.request() && request.status() != 101)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -312,7 +324,7 @@ OverlayImpl::makePrefix (std::uint32_t id)
|
||||
|
||||
std::shared_ptr<Writer>
|
||||
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);
|
||||
{
|
||||
@@ -322,13 +334,13 @@ OverlayImpl::makeRedirectResponse (PeerFinder::Slot::ptr const& slot,
|
||||
ips.append(_.address.to_string());
|
||||
}
|
||||
|
||||
beast::http::message m;
|
||||
beast::deprecated_http::message m;
|
||||
m.request(false);
|
||||
m.status(503);
|
||||
m.reason("Service Unavailable");
|
||||
m.headers.append("Remote-Address", remote_address.to_string());
|
||||
m.version(request.version());
|
||||
if (request.version() == std::make_pair(1, 0))
|
||||
m.headers.insert("Remote-Address", remote_address.to_string());
|
||||
m.version(std::make_pair(request.version / 10, request.version % 10));
|
||||
if (request.version == 10)
|
||||
{
|
||||
//?
|
||||
}
|
||||
@@ -829,16 +841,17 @@ OverlayImpl::json ()
|
||||
}
|
||||
|
||||
bool
|
||||
OverlayImpl::processRequest (beast::http::message const& req,
|
||||
OverlayImpl::processRequest (http_request_type const& req,
|
||||
Handoff& handoff)
|
||||
{
|
||||
if (req.url() != "/crawl")
|
||||
if (req.url != "/crawl")
|
||||
return false;
|
||||
|
||||
beast::http::message resp;
|
||||
beast::deprecated_http::message resp;
|
||||
resp.request(false);
|
||||
resp.status(200);
|
||||
resp.reason("OK");
|
||||
resp.version(std::make_pair(req.version / 10, req.version % 10));
|
||||
Json::Value v;
|
||||
v["overlay"] = crawl();
|
||||
handoff.response = make_JsonWriter(resp, v);
|
||||
|
||||
@@ -166,7 +166,7 @@ public:
|
||||
|
||||
Handoff
|
||||
onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
endpoint_type remote_endpoint) override;
|
||||
|
||||
PeerSequence
|
||||
@@ -254,7 +254,11 @@ public:
|
||||
|
||||
static
|
||||
bool
|
||||
isPeerUpgrade (beast::http::message const& request);
|
||||
isPeerUpgrade (http_request_type const& request);
|
||||
|
||||
static
|
||||
bool
|
||||
isPeerUpgrade (beast::deprecated_http::message const& request);
|
||||
|
||||
static
|
||||
std::string
|
||||
@@ -266,6 +270,18 @@ public:
|
||||
bool isInbound,
|
||||
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
|
||||
Active peers are only those peers that have completed the handshake
|
||||
and are running the Ripple protocol.
|
||||
@@ -282,18 +298,6 @@ public:
|
||||
Json::Value
|
||||
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 {
|
||||
|
||||
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,
|
||||
Resource::Consumer consumer,
|
||||
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)
|
||||
, fee_ (Resource::feeLightPeer)
|
||||
, 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
|
||||
PeerImp::crawl() const
|
||||
{
|
||||
auto const iter = http_message_.headers.find("Crawl");
|
||||
if (iter == http_message_.headers.end())
|
||||
auto const iter = headers_.find("Crawl");
|
||||
if (iter == headers_.end())
|
||||
return false;
|
||||
return beast::ci_equal(iter->second, "public");
|
||||
}
|
||||
@@ -586,7 +587,7 @@ PeerImp::onShutdown(error_code ec)
|
||||
void PeerImp::doAccept()
|
||||
{
|
||||
assert(read_buffer_.size() == 0);
|
||||
assert(http_message_.upgrade());
|
||||
// assert(request_.upgrade);
|
||||
|
||||
JLOG(journal_.debug()) << "doAccept: " << remote_address_;
|
||||
|
||||
@@ -601,8 +602,8 @@ void PeerImp::doAccept()
|
||||
|
||||
auto resp = makeResponse(
|
||||
! overlay_.peerFinder().config().peerPrivate,
|
||||
http_message_, remote_address_, *sharedValue);
|
||||
beast::http::write (write_buffer_, resp);
|
||||
request_, remote_address_, *sharedValue);
|
||||
beast::deprecated_http::write (write_buffer_, resp);
|
||||
|
||||
auto const protocol = BuildInfo::make_protocol(hello_.protoversion());
|
||||
JLOG(journal_.info()) << "Protocol: " << to_string(protocol);
|
||||
@@ -641,25 +642,25 @@ void PeerImp::doAccept()
|
||||
onWriteResponse(error_code(), 0);
|
||||
}
|
||||
|
||||
beast::http::message
|
||||
beast::deprecated_http::message
|
||||
PeerImp::makeResponse (bool crawl,
|
||||
beast::http::message const& req,
|
||||
http_request_type const& req,
|
||||
beast::IP::Endpoint remote,
|
||||
uint256 const& sharedValue)
|
||||
{
|
||||
beast::http::message resp;
|
||||
beast::deprecated_http::message resp;
|
||||
resp.request(false);
|
||||
resp.status(101);
|
||||
resp.reason("Switching Protocols");
|
||||
resp.version(req.version());
|
||||
resp.headers.append("Connection", "Upgrade");
|
||||
resp.headers.append("Upgrade", "RTXP/1.2");
|
||||
resp.headers.append("Connect-AS", "Peer");
|
||||
resp.headers.append("Server", BuildInfo::getFullVersionString());
|
||||
resp.headers.append ("Crawl", crawl ? "public" : "private");
|
||||
resp.version(std::make_pair(req.version / 10, req.version % 10));
|
||||
resp.headers.insert("Connection", "Upgrade");
|
||||
resp.headers.insert("Upgrade", "RTXP/1.2");
|
||||
resp.headers.insert("Connect-AS", "Peer");
|
||||
resp.headers.insert("Server", BuildInfo::getFullVersionString());
|
||||
resp.headers.insert("Crawl", crawl ? "public" : "private");
|
||||
protocol::TMHello hello = buildHello(sharedValue,
|
||||
overlay_.setup().public_ip, remote, app_);
|
||||
appendHello(resp, hello);
|
||||
appendHello(resp.headers, hello);
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
@@ -153,8 +153,9 @@ private:
|
||||
Resource::Charge fee_;
|
||||
PeerFinder::Slot::ptr slot_;
|
||||
beast::streambuf read_buffer_;
|
||||
beast::http::message http_message_;
|
||||
beast::http::body http_body_;
|
||||
http_request_type request_;
|
||||
beast::deprecated_http::message response_;
|
||||
beast::http::headers<std::allocator<char>> const& headers_;
|
||||
beast::streambuf write_buffer_;
|
||||
std::queue<Message::pointer> send_queue_;
|
||||
bool gracefulClose_ = false;
|
||||
@@ -171,7 +172,7 @@ public:
|
||||
|
||||
/** Create an active incoming peer from an established ssl connection. */
|
||||
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,
|
||||
Resource::Consumer consumer,
|
||||
std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
@@ -182,7 +183,7 @@ public:
|
||||
template <class Buffers>
|
||||
PeerImp (Application& app, std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
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,
|
||||
PublicKey const& publicKey, id_t id,
|
||||
OverlayImpl& overlay);
|
||||
@@ -359,8 +360,8 @@ private:
|
||||
void
|
||||
doAccept();
|
||||
|
||||
beast::http::message
|
||||
makeResponse (bool crawl, beast::http::message const& req,
|
||||
beast::deprecated_http::message
|
||||
makeResponse (bool crawl, http_request_type const& req,
|
||||
beast::IP::Endpoint remoteAddress,
|
||||
uint256 const& sharedValue);
|
||||
|
||||
@@ -476,7 +477,7 @@ private:
|
||||
template <class Buffers>
|
||||
PeerImp::PeerImp (Application& app, std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
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,
|
||||
PublicKey const& publicKey, id_t id,
|
||||
OverlayImpl& overlay)
|
||||
@@ -504,7 +505,8 @@ PeerImp::PeerImp (Application& app, std::unique_ptr<beast::asio::ssl_bundle>&& s
|
||||
, usage_ (usage)
|
||||
, fee_ (Resource::feeLightPeer)
|
||||
, 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(
|
||||
boost::asio::buffer_size(buffers)), buffers));
|
||||
|
||||
@@ -154,43 +154,41 @@ buildHello (
|
||||
}
|
||||
|
||||
void
|
||||
appendHello (beast::http::message& m,
|
||||
appendHello (beast::http::headers<std::allocator<char>>& h,
|
||||
protocol::TMHello const& hello)
|
||||
{
|
||||
auto& h = m.headers;
|
||||
|
||||
//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()));
|
||||
|
||||
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())
|
||||
h.append ("Ledger", std::to_string (hello.ledgerindex()));
|
||||
h.insert ("Ledger", std::to_string (hello.ledgerindex()));
|
||||
|
||||
if (hello.has_ledgerclosed())
|
||||
h.append ("Closed-Ledger", beast::base64_encode (
|
||||
h.insert ("Closed-Ledger", beast::base64_encode (
|
||||
hello.ledgerclosed()));
|
||||
|
||||
if (hello.has_ledgerprevious())
|
||||
h.append ("Previous-Ledger", beast::base64_encode (
|
||||
h.insert ("Previous-Ledger", beast::base64_encode (
|
||||
hello.ledgerprevious()));
|
||||
|
||||
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())));
|
||||
|
||||
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())));
|
||||
}
|
||||
|
||||
std::vector<ProtocolVersion>
|
||||
parse_ProtocolVersions (std::string const& s)
|
||||
parse_ProtocolVersions(boost::string_ref const& value)
|
||||
{
|
||||
static boost::regex re (
|
||||
"^" // start of line
|
||||
@@ -201,7 +199,7 @@ parse_ProtocolVersions (std::string const& s)
|
||||
"$" // The end of the string
|
||||
, boost::regex_constants::optimize);
|
||||
|
||||
auto const list = beast::rfc2616::split_commas (s);
|
||||
auto const list = beast::rfc2616::split_commas(value);
|
||||
std::vector<ProtocolVersion> result;
|
||||
for (auto const& s : list)
|
||||
{
|
||||
@@ -224,10 +222,8 @@ parse_ProtocolVersions (std::string const& s)
|
||||
}
|
||||
|
||||
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,
|
||||
// it is supplanted by the values in the headers.
|
||||
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");
|
||||
if (iter != h.end())
|
||||
hello.set_fullversion (iter->second);
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
#include <beast/http/message.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include "ripple.pb.h"
|
||||
|
||||
namespace ripple {
|
||||
@@ -59,14 +58,14 @@ buildHello (uint256 const& sharedValue,
|
||||
|
||||
/** Insert HTTP headers based on the TMHello protocol message. */
|
||||
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.
|
||||
@return A protocol message on success; an empty optional
|
||||
if the parsing failed.
|
||||
*/
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
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 <beast/asio/ssl_bundle.h>
|
||||
#include <beast/http/message.h>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
@@ -61,18 +60,18 @@ struct Handler
|
||||
Handoff
|
||||
onHandoff (Session& session,
|
||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) = 0;
|
||||
|
||||
virtual
|
||||
Handoff
|
||||
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;
|
||||
/** @} */
|
||||
|
||||
/** 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;
|
||||
|
||||
/** Called when the session ends.
|
||||
|
||||
@@ -21,10 +21,15 @@
|
||||
#define RIPPLE_SERVER_HANDOFF_H_INCLUDED
|
||||
|
||||
#include <ripple/server/Writer.h>
|
||||
#include <beast/http/message.h>
|
||||
#include <beast/http/streambuf_body.h>
|
||||
#include <memory>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
using http_request_type =
|
||||
beast::http::request<beast::http::streambuf_body>;
|
||||
|
||||
/** Used to indicate the result of a server connection handoff. */
|
||||
struct Handoff
|
||||
{
|
||||
|
||||
@@ -144,16 +144,16 @@ write(Streambuf& buf, Json::Value const& json)
|
||||
*/
|
||||
template <class = void>
|
||||
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 body;
|
||||
write(body, json);
|
||||
// VFALCO TODO Better way to set a field
|
||||
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.append("Content-Type", "application/json");
|
||||
m.headers.insert("Content-Type", "application/json");
|
||||
write(prebody, m);
|
||||
return std::make_shared<streambufs_writer>(
|
||||
std::move(prebody), std::move(body));
|
||||
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
/** Fills in boilerplate HTTP header field values. */
|
||||
static
|
||||
void
|
||||
appendStandardFields (beast::http::message& message);
|
||||
appendStandardFields (beast::deprecated_http::message& message);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -66,14 +66,9 @@ public:
|
||||
|
||||
/** Returns the current HTTP request. */
|
||||
virtual
|
||||
beast::http::message&
|
||||
http_request_type&
|
||||
request() = 0;
|
||||
|
||||
/** Returns the Content-Body of the current HTTP request. */
|
||||
virtual
|
||||
beast::http::body const&
|
||||
body() = 0;
|
||||
|
||||
/** Send a copy of data asynchronously. */
|
||||
/** @{ */
|
||||
void
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
#include <ripple/beast/net/IPAddressConversion.h>
|
||||
#include <beast/asio/placeholders.h>
|
||||
#include <beast/asio/ssl_error.h> // for is_short_read?
|
||||
#include <beast/http/read.h>
|
||||
#include <beast/http/message.h>
|
||||
#include <beast/http/parser.h>
|
||||
#include <beast/http/streambuf_body.h>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
@@ -95,8 +97,7 @@ protected:
|
||||
std::size_t nid_;
|
||||
|
||||
boost::asio::streambuf read_buf_;
|
||||
beast::http::message message_;
|
||||
beast::http::body body_;
|
||||
http_request_type message_;
|
||||
std::vector<buffer> wq_;
|
||||
std::vector<buffer> wq2_;
|
||||
std::mutex mutex_;
|
||||
@@ -186,18 +187,12 @@ protected:
|
||||
return beast::IPAddressConversion::from_asio(remote_address_);
|
||||
}
|
||||
|
||||
beast::http::message&
|
||||
http_request_type&
|
||||
request() override
|
||||
{
|
||||
return message_;
|
||||
}
|
||||
|
||||
beast::http::body const&
|
||||
body() override
|
||||
{
|
||||
return body_;
|
||||
}
|
||||
|
||||
void
|
||||
write (void const* buffer, std::size_t bytes) override;
|
||||
|
||||
@@ -319,64 +314,12 @@ void
|
||||
BaseHTTPPeer<Impl>::do_read (yield_context yield)
|
||||
{
|
||||
complete_ = false;
|
||||
|
||||
error_code ec;
|
||||
bool eof = false;
|
||||
body_.clear();
|
||||
beast::http::parser parser (message_, body_, true);
|
||||
for(;;)
|
||||
{
|
||||
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");
|
||||
}
|
||||
beast::http::async_read(impl().stream_,
|
||||
read_buf_, message_, yield[ec]);
|
||||
// VFALCO What if the connection was closed?
|
||||
cancel_timer();
|
||||
do_request();
|
||||
}
|
||||
|
||||
// Send everything in the write queue.
|
||||
@@ -513,7 +456,7 @@ BaseHTTPPeer<Impl>::complete()
|
||||
return strand_.post(std::bind (&BaseHTTPPeer<Impl>::complete,
|
||||
impl().shared_from_this()));
|
||||
|
||||
message_ = beast::http::message{};
|
||||
message_ = {};
|
||||
complete_ = true;
|
||||
|
||||
{
|
||||
|
||||
@@ -108,7 +108,7 @@ PlainHTTPPeer::do_request()
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (ec)
|
||||
return fail (ec, "request");
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <ripple/server/Port.h>
|
||||
#include <beast/http/rfc2616.h>
|
||||
#include <beast/module/core/text/LexicalCast.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -169,7 +169,7 @@ parse_Port (ParsedPort& port, Section const& section, std::ostream& log)
|
||||
if (*port.port == 0)
|
||||
Throw<std::exception> ();
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
catch (std::exception const&)
|
||||
{
|
||||
log <<
|
||||
"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> (
|
||||
beast::lexicalCastThrow<std::uint16_t>(lim));
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
catch (std::exception const&)
|
||||
{
|
||||
log <<
|
||||
"Invalid value '" << lim << "' for key " <<
|
||||
|
||||
@@ -116,7 +116,7 @@ ServerHandlerImp::onAccept (Session& session,
|
||||
auto
|
||||
ServerHandlerImp::onHandoff (Session& session,
|
||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) ->
|
||||
Handoff
|
||||
{
|
||||
@@ -138,7 +138,7 @@ ServerHandlerImp::onHandoff (Session& session,
|
||||
auto
|
||||
ServerHandlerImp::onHandoff (Session& session,
|
||||
boost::asio::ip::tcp::socket&& socket,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) ->
|
||||
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
|
||||
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.
|
||||
void
|
||||
ServerHandlerImp::processSession (std::shared_ptr<Session> const& session,
|
||||
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,
|
||||
[&]
|
||||
{
|
||||
@@ -233,7 +270,7 @@ ServerHandlerImp::processSession (std::shared_ptr<Session> const& session,
|
||||
return std::string{};
|
||||
}());
|
||||
|
||||
if (session->request().keep_alive())
|
||||
if(is_keep_alive(session->request()))
|
||||
session->complete();
|
||||
else
|
||||
session->close (true);
|
||||
@@ -425,9 +462,9 @@ ServerHandlerImp::processRequest (Port const& port,
|
||||
// Returns `true` if the HTTP request is a Websockets Upgrade
|
||||
// http://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header#Use_with_WebSockets
|
||||
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 false;
|
||||
}
|
||||
@@ -457,7 +494,7 @@ ServerHandlerImp::authorized (Port const& port,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
ServerHandler::appendStandardFields (beast::http::message& message)
|
||||
ServerHandler::appendStandardFields (beast::deprecated_http::message& message)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -95,12 +95,12 @@ private:
|
||||
Handoff
|
||||
onHandoff (Session& session,
|
||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) override;
|
||||
|
||||
Handoff
|
||||
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;
|
||||
void
|
||||
onRequest (Session& session) override;
|
||||
@@ -126,7 +126,7 @@ private:
|
||||
|
||||
private:
|
||||
bool
|
||||
isWebsocketUpgrade (beast::http::message const& request);
|
||||
isWebsocketUpgrade (http_request_type const& request);
|
||||
|
||||
bool
|
||||
authorized (Port const& port,
|
||||
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
Handoff
|
||||
onHandoff (Session& session,
|
||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) override
|
||||
{
|
||||
return Handoff{};
|
||||
@@ -115,7 +115,7 @@ public:
|
||||
|
||||
Handoff
|
||||
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
|
||||
{
|
||||
return Handoff{};
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
onRequest (Session& session) override
|
||||
{
|
||||
session.write (std::string ("Hello, world!\n"));
|
||||
if (session.request().keep_alive())
|
||||
if (is_keep_alive(session.request()))
|
||||
session.complete();
|
||||
else
|
||||
session.close (true);
|
||||
@@ -309,7 +309,7 @@ public:
|
||||
Handoff
|
||||
onHandoff (Session& session,
|
||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) override
|
||||
{
|
||||
return Handoff{};
|
||||
@@ -317,7 +317,7 @@ public:
|
||||
|
||||
Handoff
|
||||
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
|
||||
{
|
||||
return Handoff{};
|
||||
|
||||
@@ -122,8 +122,8 @@ public:
|
||||
|
||||
read_until(stream_, bin_, "\r\n\r\n");
|
||||
beast::streambuf body;
|
||||
beast::http::message m;
|
||||
beast::http::parser p(
|
||||
beast::deprecated_http::message m;
|
||||
beast::deprecated_http::parser p(
|
||||
[&](void const* data, std::size_t size)
|
||||
{
|
||||
body.commit(buffer_copy(
|
||||
@@ -132,11 +132,12 @@ public:
|
||||
|
||||
for(;;)
|
||||
{
|
||||
auto const result = p.write(bin_.data());
|
||||
if (result.first)
|
||||
Throw<boost::system::system_error>(result.first);
|
||||
|
||||
bin_.consume(result.second);
|
||||
boost::system::error_code ec;
|
||||
auto used = p.write(bin_.data(), ec);
|
||||
if(ec)
|
||||
Throw<boost::system::system_error>(ec);
|
||||
bin_.consume(used);
|
||||
// VFALCO What do we do if bin_ still has data?
|
||||
if(p.complete())
|
||||
break;
|
||||
bin_.commit(stream_.read_some(
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
// Include this to get all the basic includes included, to prevent errors
|
||||
#include <ripple/beast/core/core.unity.cpp>
|
||||
|
||||
#include <beast/http/HTTP.unity.cpp>
|
||||
|
||||
#include <beast/unit_test/define_print.cpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -543,13 +543,13 @@ public:
|
||||
streambuf sb;
|
||||
read_until(s_, sb, "\r\n\r\n");
|
||||
using namespace beast;
|
||||
http::body b;
|
||||
http::message m;
|
||||
http::parser p(m, b, false);
|
||||
auto const result = p.write(sb.data());
|
||||
if (result.first || ! p.complete())
|
||||
throw std::runtime_error(result.first.message());
|
||||
sb.consume(result.second);
|
||||
deprecated_http::body b;
|
||||
deprecated_http::message m;
|
||||
deprecated_http::parser p(m, b, false);
|
||||
auto const used = p.write(sb.data(), ec);
|
||||
if (ec || ! p.complete())
|
||||
throw std::runtime_error(ec.message());
|
||||
sb.consume(used);
|
||||
}
|
||||
|
||||
// write a text message
|
||||
|
||||
Reference in New Issue
Block a user