0

Below is my sample restful web service created using C++ and Boost Beast.

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio.hpp>
#include <chrono>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <memory>
#include <string>

namespace beast = boost::beast;
namespace http = beast::http; 
namespace net = boost::asio; 
using tcp = boost::asio::ip::tcp; 

namespace my_program_state
{
    std::size_t
    request_count()
    {
        static std::size_t count = 0;
        return ++count;
    }

    std::time_t
    now()
    {
        return std::time(0);
    }
}

class http_connection : public std::enable_shared_from_this<http_connection>
{
    public:
        http_connection(tcp::socket socket)
        : socket_(std::move(socket))
        {
        }

        void start()
        {
            read_request();
            check_deadline();
        }

    private:
        tcp::socket socket_;
        beast::flat_buffer buffer_{8192};
        http::request<http::dynamic_body> request_;
        http::response<http::dynamic_body> response_;
        net::steady_timer deadline_{ socket_.get_executor(), std::chrono::seconds(60) };

        void read_request()
        {
             auto self = shared_from_this();
             http::async_read(
                 socket_,
                 buffer_,
                 request_,
                 [self](beast::error_code ec, std::size_t bytes_transferred)
                 {
                      boost::ignore_unused(bytes_transferred);
                      if(!ec)
                         self->process_request();
                 }
             );
        }

        void process_request()
        {
            response_.version(request_.version());
            response_.keep_alive(false);

            switch(request_.method())
            {
                case http::verb::get:
                    response_.result(http::status::ok);
                    response_.set(http::field::server, "Beast");
                    create_response();
                    break;

                default:
                    response_.result(http::status::bad_request);
                    response_.set(http::field::content_type, "text/plain");
                    beast::ostream(response_.body())
                        << "Invalid request-method '"
                        << std::string(request_.method_string())
                        << "'";
                    break;
             }

             write_response();
        }

        void create_response()
        {
            if(request_.target() == "/json")
            {
                response_.set(http::field::content_type, "application/json");
                response_.set(http::field::access_control_allow_origin, "*");
                response_.set(http::field::access_control_allow_headers, "*");
                response_.set(http::field::access_control_allow_methods, "GET, POST, PATCH, PUT, DELETE, OPTIONS");
                beast::ostream(response_.body())
                    <<  "{\"a\":{\"b\":\"c\"}}";
            }
            else
            {
                response_.result(http::status::not_found);
                response_.set(http::field::content_type, "text/plain");
                beast::ostream(response_.body()) << "File not found\r\n";
            }
        }

        void write_response()
        {
            auto self = shared_from_this();
            response_.content_length(response_.body().size());
            http::async_write(
               socket_,
               response_,
               [self](beast::error_code ec, std::size_t)
               {
                  self->socket_.shutdown(tcp::socket::shutdown_send, ec);
                  self->deadline_.cancel();
               }
            );
        }

        void check_deadline()
        {
            auto self = shared_from_this();
            deadline_.async_wait(
                [self](beast::error_code ec)
                {
                    if(!ec)
                    {
                        self->socket_.close(ec);
                    }
                }
             );
        }
};

void http_server(tcp::acceptor& acceptor, tcp::socket& socket)
{
  acceptor.async_accept(socket, [&](beast::error_code ec) {
      if(!ec) std::make_shared<http_connection>(std::move(socket))->start();
      http_server(acceptor, socket);
  });
}

int main(int argc, char* argv[])
{
    try
    {
        if(argc != 3)
        {
            std::cerr << "Usage: " << argv[0] << " <address> <port>\n";
            std::cerr << "  For IPv4, try:\n";
            std::cerr << "    receiver 0.0.0.0 80\n";
            std::cerr << "  For IPv6, try:\n";
            std::cerr << "    receiver 0::0 80\n";
            return EXIT_FAILURE;
        }

        auto const address = net::ip::make_address(argv[1]);
        unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
        net::io_context ioc{1};
        tcp::acceptor acceptor{ioc, {address, port}};
        tcp::socket socket{ioc};
        http_server(acceptor, socket);
        ioc.run();
    }
    catch(std::exception const& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}

I run this web server as following.

./main 192.168.10.100 8081

Below is my JavaScript client making a GET request from another IP address e.g. 192.168.10.101.

window.axios.get("http://192.168.10.100:8081/json")
    .then(res => {
        console.log(res.data);
    })
    .catch(err => {
        console.log(err.response);
    });

Due to Referrer Policystrict-origin-when-cross-origin, I cannot get JSON data responded by the web service. I have already added response headers but it still does not help. How can I solve this issue?

oguz ismail
  • 1
  • 16
  • 47
  • 69
O Connor
  • 4,236
  • 15
  • 50
  • 91
  • I think you need to use https if you like to use cross-origin in recent browser versions. https://stackoverflow.com/questions/68567653/do-i-have-to-switch-to-https-to-use-sharedarraybuffer-in-chrome-92 – Koronis Neilos Jul 25 '22 at 11:14
  • The Restful web service in C++ above works fine. The problem was the `window.axios` on the client side. When using `fetch("IP_ADDRESS", { method: 'GET' })` on the client side, everything works fine. – O Connor Jul 26 '22 at 08:46

1 Answers1

0

Hi Did you try something like as follows may be it could help

//System Includes
  #include <map>
  #include <thread>
  #include <memory>
  #include <functional>
  //Project Includes
  #include <restbed>

 //External Includes
 #include <catch.hpp>

  //System Namespaces
    using std::thread;
    using std::string;
    using std::multimap;
    using std::shared_ptr;
    using std::make_shared;
   //Project Namespaces
    using namespace restbed;

    //External Namespaces

    void get_handler( const shared_ptr< Session > session )
      {
         session->close( OK, "", { { "Connection", "close" } } );
      }

    TEST_CASE( "test unsupported non alphanumeric header names.", "[http]" 
  )
 {
 auto resource = make_shared< Resource >( );
 resource->set_path( "test" );
 resource->set_method_handler( "GET", get_handler );

auto settings = make_shared< Settings >( );
settings->set_port( 1984 );
settings->set_default_header( "Access-Control-Allow-Origin", "*" );

shared_ptr< thread > worker = nullptr;

Service service;
service.publish( resource );
service.set_ready_handler( [ &worker ]( Service & service )
{
    worker = make_shared< thread >( [ &service ] ( )
    {
        auto request = make_shared< Request >( );
        request->set_method( "GET" );
        request->set_port( 1984 );
        request->set_host( "localhost" );
        request->set_path( "/test" );
        
        auto response = Http::sync( request );
        
        REQUIRE( 200 == response->get_status_code( ) );
        REQUIRE( "*" == response->get_header( "Access-Control-Allow-Origin" 
    ) );
        
        service.stop( );
    } );
} );
service.start( settings );
worker->join( );

}

ISK
  • 85
  • 1
  • 9