Hello,

 

> Would you mind sharing your code (perhaps in a git repo) so that I can reproduce, debug and advise?

 

No problem, the code is just a slightly modified version of the example:

 

//

// Copyright (c) 2016-2019 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)

//

// Official repository: https://github.com/boostorg/beast

//

 

//------------------------------------------------------------------------------

//

// Example: HTTP server, asynchronous

//

//------------------------------------------------------------------------------

 

#include <boost/beast/core.hpp>

#include <boost/beast/http.hpp>

#include <boost/beast/version.hpp>

#include <boost/asio/dispatch.hpp>

#include <boost/asio/strand.hpp>

#include <boost/asio/buffers_iterator.hpp>

#include <boost/config.hpp>

#include <algorithm>

#include <cstdlib>

#include <functional>

#include <iostream>

#include <memory>

#include <string>

#include <thread>

#include <vector>

 

namespace beast = boost::beast;         // from <boost/beast.hpp>

namespace http = beast::http;           // from <boost/beast/http.hpp>

namespace net = boost::asio;            // from <boost/asio.hpp>

using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>

 

// Return a reasonable mime type based on the extension of a file.

beast::string_view

mime_type(beast::string_view path)

{

                using beast::iequals;

                auto const ext = [&path]

                {

                               auto const pos = path.rfind(".");

                               if(pos == beast::string_view::npos)

                                               return beast::string_view{};

                               return path.substr(pos);

                }();

                if(iequals(ext, ".htm"))  return "text/html";

                if(iequals(ext, ".html")) return "text/html";

                if(iequals(ext, ".php"))  return "text/html";

                if(iequals(ext, ".css"))  return "text/css";

                if(iequals(ext, ".txt"))  return "text/plain";

                if(iequals(ext, ".js"))   return "application/javascript";

                if(iequals(ext, ".json")) return "application/json";

                if(iequals(ext, ".xml"))  return "application/xml";

                if(iequals(ext, ".swf"))  return "application/x-shockwave-flash";

                if(iequals(ext, ".flv"))  return "video/x-flv";

                if(iequals(ext, ".png"))  return "image/png";

                if(iequals(ext, ".jpe"))  return "image/jpeg";

                if(iequals(ext, ".jpeg")) return "image/jpeg";

                if(iequals(ext, ".jpg"))  return "image/jpeg";

                if(iequals(ext, ".gif"))  return "image/gif";

                if(iequals(ext, ".bmp"))  return "image/bmp";

                if(iequals(ext, ".ico"))  return "image/vnd.microsoft.icon";

                if(iequals(ext, ".tiff")) return "image/tiff";

                if(iequals(ext, ".tif"))  return "image/tiff";

                if(iequals(ext, ".svg"))  return "image/svg+xml";

                if(iequals(ext, ".svgz")) return "image/svg+xml";

                return "application/text";

}

 

// Append an HTTP rel-path to a local filesystem path.

// The returned path is normalized for the platform.

std::string

path_cat(

                beast::string_view base,

                beast::string_view path)

{

                if(base.empty())

                               return std::string(path);

                std::string result(base);

#ifdef BOOST_MSVC

                char constexpr path_separator = '\\';

                if(result.back() == path_separator)

                               result.resize(result.size() - 1);

                result.append(path.data(), path.size());

                for(auto& c : result)

                               if(c == '/')

                                               c = path_separator;

#else

                char constexpr path_separator = '/';

                if(result.back() == path_separator)

                               result.resize(result.size() - 1);

                result.append(path.data(), path.size());

#endif

                return result;

}

 

// This function produces an HTTP response for the given

// request. The type of the response object depends on the

// contents of the request, so the interface requires the

// caller to pass a generic lambda for receiving the response.

template<

                class Body, class Allocator,

                class Send>

void

handle_request(

                beast::string_view doc_root,

                http::request<Body, http::basic_fields<Allocator>>&& req,

                Send&& send)

{

                // Returns a bad request response

                auto const bad_request =

                [&req](beast::string_view why)

                {

                               http::response<http::string_body> res{http::status::bad_request, req.version()};

                               res.set(http::field::server, BOOST_BEAST_VERSION_STRING);

                               res.set(http::field::content_type, "text/html");

                               res.keep_alive(req.keep_alive());

                               res.body() = std::string(why);

                               res.prepare_payload();

                               return res;

                };

 

                // Returns a not found response

                auto const not_found =

                [&req](beast::string_view target)

                {

                               http::response<http::string_body> res{http::status::not_found, req.version()};

                               res.set(http::field::server, BOOST_BEAST_VERSION_STRING);

                               res.set(http::field::content_type, "text/html");

                               res.keep_alive(req.keep_alive());

                               res.body() = "The resource '" + std::string(target) + "' was not found.";

                               res.prepare_payload();

                               return res;

                };

 

                // Returns a server error response

                auto const server_error =

                [&req](beast::string_view what)

                {

                               http::response<http::string_body> res{http::status::internal_server_error, req.version()};

                               res.set(http::field::server, BOOST_BEAST_VERSION_STRING);

                               res.set(http::field::content_type, "text/html");

                               res.keep_alive(req.keep_alive());

                               res.body() = "An error occurred: '" + std::string(what) + "'";

                               res.prepare_payload();

                               return res;

                };

 

                if (req.method() == http::verb::post && req.target()=="/xxx" )

                {

                               for (const auto &h:req)

                                               printf("heder: %s=%s\n", std::string(h.name_string()).c_str(), std::string(h.value()).c_str());

                               printf("body as string:\n");

                               std::string body{ boost::asio::buffers_begin(req.body().data()),

                                                 boost::asio::buffers_end(req.body().data()) };

                               printf("%s", body.c_str());

                               printf("end of body as string\n");

                               printf("body with iterator:\n");

                               const auto begin = boost::asio::buffers_begin(req.body().data());

                               const auto end   = boost::asio::buffers_end(req.body().data());

                               unsigned x=0;

                               for (auto it = begin; it != end; it++)

                                               putchar(*it);

                               printf("end of body with iterator\n");

                }

 

                // Make sure we can handle the method

                if( req.method() != http::verb::get &&

                               req.method() != http::verb::head)

                               return send(bad_request("Unknown HTTP-method"));

 

                // Request path must be absolute and not contain "..".

                if( req.target().empty() ||

                               req.target()[0] != '/' ||

                               req.target().find("..") != beast::string_view::npos)

                               return send(bad_request("Illegal request-target"));

 

                // Build the path to the requested file

                std::string path = path_cat(doc_root, req.target());

                if(req.target().back() == '/')

                               path.append("index.html");

 

                // Attempt to open the file

                beast::error_code ec;

                http::file_body::value_type body;

                body.open(path.c_str(), beast::file_mode::scan, ec);

 

                // Handle the case where the file doesn't exist

                if(ec == beast::errc::no_such_file_or_directory)

                               return send(not_found(req.target()));

 

                // Handle an unknown error

                if(ec)

                               return send(server_error(ec.message()));

 

                // Cache the size since we need it after the move

                auto const size = body.size();

 

                // Respond to HEAD request

                if(req.method() == http::verb::head)

                {

                               http::response<http::empty_body> res{http::status::ok, req.version()};

                               res.set(http::field::server, BOOST_BEAST_VERSION_STRING);

                               res.set(http::field::content_type, mime_type(path));

                               res.content_length(size);

                               res.keep_alive(req.keep_alive());

                               return send(std::move(res));

                }

 

                // Respond to GET request

                http::response<http::file_body> res{

                               std::piecewise_construct,

                               std::make_tuple(std::move(body)),

                               std::make_tuple(http::status::ok, req.version())};

                res.set(http::field::server, BOOST_BEAST_VERSION_STRING);

                res.set(http::field::content_type, mime_type(path));

                res.content_length(size);

                res.keep_alive(req.keep_alive());

                return send(std::move(res));

}

 

//------------------------------------------------------------------------------

 

// Report a failure

void

fail(beast::error_code ec, char const* what)

{

                std::cerr << what << ": " << ec.message() << "\n";

}

 

// Handles an HTTP server connection

class session : public std::enable_shared_from_this<session>

{

                // This is the C++11 equivalent of a generic lambda.

                // The function object is used to send an HTTP message.

                struct send_lambda

                {

                               session& self_;

 

                               explicit

                               send_lambda(session& self)

                                               : self_(self)

                               {

                               }

 

                               template<bool isRequest, class Body, class Fields>

                               void

                               operator()(http::message<isRequest, Body, Fields>&& msg) const

                               {

                                               // The lifetime of the message has to extend

                                               // for the duration of the async operation so

                                               // we use a shared_ptr to manage it.

                                               auto sp = std::make_shared<

                                                               http::message<isRequest, Body, Fields>>(std::move(msg));

 

                                               // Store a type-erased version of the shared

                                               // pointer in the class to keep it alive.

                                               self_.res_ = sp;

 

                                               // Write the response

                                               http::async_write(

                                                               self_.stream_,

                                                               *sp,

                                                               beast::bind_front_handler(

                                                                               &session::on_write,

                                                                               self_.shared_from_this(),

                                                                               sp->need_eof()));

                               }

                };

 

                beast::tcp_stream stream_;

                beast::flat_buffer buffer_;

                std::shared_ptr<std::string const> doc_root_;

//            http::request<http::string_body> req_;

                http::request<http::dynamic_body> req_;

                std::shared_ptr<void> res_;

                send_lambda lambda_;

 

public:

                // Take ownership of the stream

                session(

                               tcp::socket&& socket,

                               std::shared_ptr<std::string const> const& doc_root)

                               : stream_(std::move(socket))

                               , doc_root_(doc_root)

                               , lambda_(*this)

                {

                }

 

                // Start the asynchronous operation

                void

                run()

                {

                               // We need to be executing within a strand to perform async operations

                               // on the I/O objects in this session. Although not strictly necessary

                               // for single-threaded contexts, this example code is written to be

                               // thread-safe by default.

                               net::dispatch(stream_.get_executor(),

                                                                                              beast::bind_front_handler(

                                                                                                              &session::do_read,

                                                                                                              shared_from_this()));

                }

 

                void

                do_read()

                {

                               // Make the request empty before reading,

                               // otherwise the operation behavior is undefined.

                               req_ = {};

 

                               // Set the timeout.

                               stream_.expires_after(std::chrono::seconds(30));

 

                               // Read a request

                               http::async_read(stream_, buffer_, req_,

                                               beast::bind_front_handler(

                                                               &session::on_read,

                                                               shared_from_this()));

                }

 

                void

                on_read(

                               beast::error_code ec,

                               std::size_t bytes_transferred)

                {

                               boost::ignore_unused(bytes_transferred);

 

                               // This means they closed the connection

                               if(ec == http::error::end_of_stream)

                                                return do_close();

 

                               if(ec)

                                               return fail(ec, "read");

 

                               // Send the response

                               handle_request(*doc_root_, std::move(req_), lambda_);

                }

 

                void

                on_write(

                               bool close,

                               beast::error_code ec,

                               std::size_t bytes_transferred)

                {

                               boost::ignore_unused(bytes_transferred);

 

                               if(ec)

                                               return fail(ec, "write");

 

                               if(close)

                               {

                                               // This means we should close the connection, usually because

                                               // the response indicated the "Connection: close" semantic.

                                               return do_close();

                               }

 

                               // We're done with the response so delete it

                               res_ = nullptr;

 

                               // Read another request

                               do_read();

                }

 

                void

                do_close()

                {

                               // Send a TCP shutdown

                               beast::error_code ec;

                               stream_.socket().shutdown(tcp::socket::shutdown_send, ec);

 

                               // At this point the connection is closed gracefully

                }

};

 

//------------------------------------------------------------------------------

 

// Accepts incoming connections and launches the sessions

class listener : public std::enable_shared_from_this<listener>

{

                net::io_context& ioc_;

                tcp::acceptor acceptor_;

                std::shared_ptr<std::string const> doc_root_;

 

public:

                listener(

                               net::io_context& ioc,

                               tcp::endpoint endpoint,

                               std::shared_ptr<std::string const> const& doc_root)

                               : ioc_(ioc)

                               , acceptor_(net::make_strand(ioc))

                               , doc_root_(doc_root)

                {

                               beast::error_code ec;

 

                               // Open the acceptor

                               acceptor_.open(endpoint.protocol(), ec);

                               if(ec)

                               {

                                               fail(ec, "open");

                                               return;

                               }

 

                               // Allow address reuse

                               acceptor_.set_option(net::socket_base::reuse_address(true), ec);

                               if(ec)

                               {

                                               fail(ec, "set_option");

                                               return;

                               }

 

                               // Bind to the server address

                               acceptor_.bind(endpoint, ec);

                               if(ec)

                               {

                                               fail(ec, "bind");

                                               return;

                               }

 

                               // Start listening for connections

                               acceptor_.listen(

                                               net::socket_base::max_listen_connections, ec);

                               if(ec)

                               {

                                               fail(ec, "listen");

                                               return;

                               }

                }

 

                // Start accepting incoming connections

                void

                run()

                {

                               do_accept();

                }

 

private:

                void

                do_accept()

                {

                               // The new connection gets its own strand

                               acceptor_.async_accept(

                                               net::make_strand(ioc_),

                                               beast::bind_front_handler(

                                                               &listener::on_accept,

                                                               shared_from_this()));

                }

 

                void

                on_accept(beast::error_code ec, tcp::socket socket)

                {

                               if(ec)

                               {

                                               fail(ec, "accept");

                               }

                               else

                               {

                                               // Create the session and run it

                                               std::make_shared<session>(

                                                               std::move(socket),

                                                               doc_root_)->run();

                               }

 

                               // Accept another connection

                               do_accept();

                }

};

 

//------------------------------------------------------------------------------

 

int main(int argc, char* argv[])

{

                // Check command line arguments.

                if (argc != 4)

                {

                               std::cerr <<

                                               "Usage: http-server-async <address> <port> <doc_root>\n" <<

                                               "Example:\n" <<

                                               "    http-server-async 0.0.0.0 8080 .\n";

                               return EXIT_FAILURE;

                }

                auto const address = net::ip::make_address(argv[1]);

                auto const port = static_cast<unsigned short>(std::atoi(argv[2]));

                auto const doc_root = std::make_shared<std::string>(argv[3]);

 

                // The io_context is required for all I/O

                net::io_context ioc;

 

                // Create and launch a listening port

                std::make_shared<listener>(

                               ioc,

                               tcp::endpoint{address, port},

                               doc_root)->run();

 

                // Run the I/O service

                printf("running\n");

                ioc.run();

 

                return EXIT_SUCCESS;

}

 

 

And this is my index.html:

 

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd>

<html xmlns=http://www.w3.org/1999/xhtml>

        <body>

 

                <form action="xxx" method="post" accept-charset="utf-8" enctype="multipart/form-data">

                        <label for="field0">field 0:</label><input type="text" id="field0" name="field0"/><br/><br/>

                        <label for="field1">field 1:</label><input type="password" id="field1" name="field1"/><br/><br/>

                        <label for="field2">field 2:</label><input type="text" id="field2" name="field2"/><br/><br/>

                        <label for="field3">field 3:</label><input type="text" id="field3" name="field3"/><br/><br/>

                        <label for="field4">field 4:</label><input type="file" id="field4" name="field4"/><br/><br/>

                        <input type="submit" value="Submit"/>

                </form>

        </body>

</html>

 

 

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.