Hello,
After using boost::asio for several years I thought, I might give beast a try. I need to write a http server processing a POST request with an upload of a big file. So I thought, I could start with libs/beast/example/http/server/async. I soon found the function handle_request() and that I have to add something like
if (req.method() == http::verb::post && req.target()=="/xxx" )
to catch the http POST transaction. But since I have to process the upload of a large file, I thought that using a http::string_body might not be the best choice. I found several other body types in the documentation. I thought
buffer_body ought to be fine, since the documentation says: ‘This allows for serialization of body data coming from external sources, and incremental parsing of message body content using a fixed size buffer.’.
incremental processing of the input stream is what I need. But now, I have no clue, how to change the example to use a buffer_body.
I changed http::requesthttp::string_body req_ to http::requesthttp::buffer_body req_. But now I must process the request message in chunks.
How do I get my callback invoked for each chunk?
Without additional changes, I get a read error: need buffer.
But the documentation on buffer_body does not help me. Buffer_body does not seem to have any methods, that I can call.
It does have a member type reader, that is documented as implementation-defined. So there is nothing I can do with this reader. ☹
There is a member type value_type, that does have data, size and more mebers, but I have no idea, how I could et hold of a variable of this type containing a part of my message body.
The error message might indicate, that I need to provide a fixed size buffer to the buffer_body, but I have no idea, how to do this.
I tried to add the following code to do_read():
req_.body().data = my_buffer;
req_.body().size = sizeof(my_buffer);
It compiles, so req_body() seems to be the way to get hold on a http::buffer_body::value_type, but simply initializing the two variables does not seem to be sufficient. I also tried to set req_.body().more to false or to true, but it didn’t change anything.
I then thought, I might try a dynamic_body. This would store the entire upload in memory, but perhaps I get more familiar with the beat framework, when I try to use this body.
And in deed, I managed to write some code, that shows all request headers and the request body on stdout. To get the body, I had to copy the buffer contents into a std::string:
std::string body{ boost::asio::buffers_begin(req.body().data()),
boost::asio::buffers_end(req.body().data()) };
Since large files have to be handled by my code, this additional copy of the data is to be avoided. So I tried to iterate the body using the iterators:
const auto begin = boost::asio::buffers_begin(req.body().data());
const auto end = boost::asio::buffers_end(req.body().data());
for (auto it = begin; it != end; it++)
putchar(*it);
While it runs fine on the windows box, the loop crashes on linux in the 512th iteration in it++.
Program received signal SIGSEGV, Segmentation fault.
0x0000555555592432 in boost::intrusive::list_node_traits::get_previous (n=@0x7fffffffc118: 0x1ff) at ../boost/boost/intrusive/detail/list_node.hpp:54
54 { return n->prev_; }
(gdb) print n
$1 = (const boost::intrusive::list_node_traits::node_ptr &) @0x7fffffffc118: 0x1ff
(gdb)
Here is the call stack:
#0 0x0000555555592432 in boost::intrusive::list_node_traits::get_previous (n=@0x7fffffffc118: 0x1ff) at ../boost/boost/intrusive/detail/list_node.hpp:54
#1 boost::intrusive::list_iterator::element, boost::intrusive::list_node_traits, (boost::intrusive::link_mode_type)0, boost::intrusive::dft_tag, 1u>, true>::operator-- (this=0x7fffffffc118) at ../boost/boost/intrusive/detail/list_iterator.hpp:107
#2 std::__advance::element, boost::intrusive::list_node_traits, (boost::intrusive::link_mode_type)0, boost::intrusive::dft_tag, 1u>, true>, long> (__i=..., __n=0) at /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include/g++-v10/bits/stl_iterator_base_funcs.h:169
#3 0x000055555558daf0 in std::advance::element, boost::intrusive::list_node_traits, (boost::intrusive::link_mode_type)0, boost::intrusive::dft_tag, 1u>, true>, long> (__i=..., __n=-1) at /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include/g++-v10/bits/stl_iterator_base_funcs.h:206
#4 0x0000555555589254 in std::prev::element, boost::intrusive::list_node_traits, (boost::intrusive::link_mode_type)0, boost::intrusive::dft_tag, 1u>, true> > (__x=..., __n=1) at /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include/g++-v10/bits/stl_iterator_base_funcs.h:230
#5 0x0000555555589608 in boost::beast::basic_multi_buffer::subrange<true>::const_iterator::operator* (this=0x7fffffffc4f8) at ../boost/boost/beast/core/impl/multi_buffer.hpp:384
#6 0x0000555555589b4b in boost::asio::buffers_iterator::subrange<true>, char>::increment (this=0x7fffffffc4d0)
at ../boost/boost/asio/buffers_iterator.hpp:370
#7 0x0000555555584894 in boost::asio::buffers_iterator::subrange<true>, char>::operator++ (this=0x7fffffffc4d0)
at ../boost/boost/asio/buffers_iterator.hpp:229
#8 0x000055555557e7c0 in boost::asio::buffers_iterator::subrange<true>, char>::operator++ (this=0x7fffffffc4d0)
at ../boost/boost/asio/buffers_iterator.hpp:237
#9 0x0000555555579ba8 in handle_request >, std::allocator<char>, session::send_lambda&> (doc_root=...,
req=..., send=...) at t.cpp:164
I hope anybody can give my a hint on how to use this beast.
Right now it feels that it might be easier to write the http server using plain boost::asio.
Klebsch Mario
Funktion | R&D
Tel: +49 (0) 531 38 701 718
Raum: Braunschweig, E20
Diese E-Mail und die an sie angehängten Dateien sind ausschließlich für Personen oder Institutionen bestimmt, deren Namen oben aufgeführt sind. Sie können Informationen enthalten, die durch das Berufsgeheimnis geschützt sind und deren Weitergabe strengstens untersagt ist. Jede elektronische Nachricht kann geändert werden. ACTIA lehnt jede Verantwortung für diese Nachricht ab. Der Inhalt dieser Nachricht stellt keine Verpflichtung seitens unseres Unternehmens dar. Wenn Sie kein Empfänger sind, weisen wir Sie darauf hin, dass das Lesen, Vervielfältigen oder Verteilen strengstens untersagt ist. Wir bitten Sie daher, uns umgehend über diesen Brief zu informieren und diese Nachricht sowie eventuell beigefügte Unterlagen aus Ihrem Postfach zu löschen. Danke.
This e-mail and the files attached to it are intended exclusively for persons or institutions whose names are listed above. They may contain information that is protected by professional secrecy and the disclosure of which is strictly prohibited. Any electronic message can be modified. ACTIA declines all responsibility for this message. The content of this message does not represent a commitment on the part of our company. If you are not a recipient, we would like to point out that reading, copying or distribution is strictly prohibited. We therefore ask you to inform us immediately about this letter and to delete this message and any accompanying documents from your mailbox. Thank you.