Add Access-Control-Allow-Origin to http_listener in C ++ REST SDK

I am starting an HTTP server with web :: http :: experimental :: listener :: http_listener from Microsoft C ++ REST SDK 1.3.1 and trying to write HTML and Javascript as a client to interact with the server.

I received almost without surprise ... A request for a cross-request is blocked: a policy of the same origin prohibits reading a remote resource in ...... (Reason: CORS header "Access-Control-Allow-Origin" is missing).

How can I put Access-Control-Allow-Origin: * on the http-listener side (in C ++ code)?

Is this possible in C ++ REST 1.3.1 ?? is there any workaround besides JSONP?

Server

#include <cpprest/http_listener.h> #include <cpprest/json.h> using namespace web; using namespace web::http; using namespace web::http::experimental::listener; http_listener httpSrv; httpSrv->support(methods::GET, handle_get); void handle_get(http_request request) { const json::value response; request.reply(status_codes::OK, response); } 

Client Client with jQuery v1.12.4 (limited to jQuery UI v1.12.0)

  $("button").click(function () { $.get(rest_url, function(data, status){ console.log(status); console.log(data); }); }); 

----------------- UPDATE -----------------------

Solution from answer

SERVER

  http_listener httpSrv; httpSrv.support(methods::GET, handle_get); httpSrv.support(methods::POST, handle_post); httpSrv.support(methods::OPTIONS, handle_options); httpSrv.open().wait(); //........... void handle_options(http_request request) { http_response response(status_codes::OK); response.headers().add(U("Allow"), U("GET, POST, OPTIONS")); response.headers().add(U("Access-Control-Allow-Origin"), U("*")); response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, OPTIONS")); response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type")); request.reply(response); } void handle_get(http_request request) { request.reply(status_codes::OK, ...); } void handle_post(http_request request) { json::value jsonResponse; request .extract_json() .then([&jsonResponse](pplx::task<json::value> task) { jsonResponse = process_request(task.get()); }) .wait(); http_response response(status_codes::OK); response.headers().add(U("Access-Control-Allow-Origin"), U("*")); response.set_body(jsonResponse); request.reply(response); } 

CUSTOMER

  function requestREST(request/*json*/,onSuccess/*callback with json response*/) { $.ajax({ type: "POST", url: "...", data: JSON.stringify(request), dataType: 'json', crossDomain: true, contentType: "application/json", success: function (response) { onSuccess(response); }, timeout:3000, statusCode: { 400: function (response) { alert('Not working!'); }, 0: function (response) { alert('Not working!'); } } }); 
+5
source share
1 answer

To add server-side headers (C ++), you will need to modify the code you use to send a response.

You are currently using:

 request.reply(status_codes::OK, response); 

Instead of doing this in one layer, the idea is to compose the answer yourself, starting with an empty answer, add the desired header, set the actual body, and then send the response back to the client.

To build an empty answer, we can use the following function:

 web::http::http_response::http_response(http::status_code code) 

As described in the documentation , it will create a response with a given status code, without headers and without a body.

To access the response headers, we can use the following function:

 web::http::http_response::headers() 

The returned object will be the http_headers type , which contains the add function :

 web::http::http_headers::add(const key_type &name, const _t1 &value) 

This function will add a title to the response if it provides a name and value for the title.

When the header is set, the only thing left to set is the body. For this, the answer has a set_body function :

 web::http::http_response::set_body(const json::value &body_data) 

In the end, the full code replacing your single-line font to create an empty response, set the title and body, and then send it back will look like this:

 http_response response(status_codes::OK); response.headers().add(U("Access-Control-Allow-Origin"), U("*")); response.set_body(jsonResponse); request.reply(response); 

Note that in the last part of the code, I use the U macro to create a string literal of the target platform type. You can find more information about this U macro in the C ++ Rest SDK FAQ .

As for preflight requests using the OPTION HTTP verb, they are expected in this situation. By default, the C ++ REST SDK includes a default implementation for these requests. The default implementation can be verified in the source code :

 void details::http_listener_impl::handle_options(http_request message) { http_response response(status_codes::OK); response.headers().add(U("Allow"), get_supported_methods()); message.reply(response); } 

It basically returns a status code of 200 and adds a list of supported methods that your server can handle.

If you want to override the default implementation, for example, to add some headers used by pre-validation requests, such as Access-Control-Allow-Methods or Access-Control-Allow-Headers , you will need to add a specific handler, as you did for GET requests and POST using:

 web::http::experimental::listener::http_listener::support(const http::method &method, const std::function< void(http_request)> &handler) 

You cannot use a common handler to process an OPTION request with:

 web::http::experimental::listener::http_listener::support(const std::function<void(http_request)> &handler) 

The reason we cannot use a common handler, if we look at the source code , is that if the method does not have a specific handler and uses the HTTP verb OPTION (or TRACE), the default handler implemented by C ++ REST will be called SDK:

 // Specific method handler takes priority over general. const method &mtd = msg.method(); if(m_supported_methods.count(mtd)) { m_supported_methods[mtd](msg); } else if(mtd == methods::OPTIONS) { handle_options(msg); } 
+4
source

All Articles