I'm just starting with RESTful programming and trying to make a program in c++ using the Casablanca sdk (https://github.com/Microsoft/cpprestsdk). I know that I need to use GET, POST, PUT and DEL methods to do data transfer etc. But I cant seem to find any examples on how to do this. I currently need to send an integer value to the server from the client and get a Boolean response from the server. I cant find any good examples in Casablanca's documentation or the web. Any help regarding how to do this simple transfer would be appreciated.
Spending more time to explore the documentation and various examples on the internet would probably have got you the answer.
Basically, you have to set up a http listener, as the server, that will listen to client request at a particular url.
Then a client can send data on that url, to communicate with it.
Nevertheless, if you want to exchange data in json format,
Server would look something like this
void handle_post(http_request request)
{
json::value temp;
request.extract_json() //extracts the request content into a json
.then([&temp](pplx::task<json::value> task)
{
temp = task.get();
})
.wait();
//do whatever you want with 'temp' here
request.reply(status_codes::OK, temp); //send the reply as a json.
}
int main()
{
http_listener listener(L"http://localhost/restdemo"); //define a listener on this url.
listener.support(methods::POST, handle_post); //'handle_post' is the function this listener will go to when it receives a POST request.
try
{
listener
.open() //start listening
.then([&listener](){TRACE(L"\nstarting to listen\n");})
.wait();
while (true);
}
catch (exception const & e)
{
wcout << e.what() << endl;
}
}
Client would be,
int main()
{
json::value client_temp;
http_client client(L"http://localhost");
//insert data into the json e.g : json::value(54)
client.request(methods::POST, L"/restdemo", object)
.then([](http_response response)
{
if (response.status_code() == status_codes::OK)
{
return response.extract_json();
}
return pplx::task_from_result(json::value());
})
.then([&client_temp ](pplx::task<json::value> previousTask)
{
client_temp = previousTask.get();
})
.wait();
}
Your server reply will be stored into 'client_temp'
Related
I have implemented a proxy with the boost beast library, where I have used the
async https server and client examples from boost organization. In my proxy I
was using the http::request<http::string_body> and
http::response<http::string_body> types of messages, as used in the examples.
This proxy works well, except that it cannot receive (download) big files and
streams.
So for that purpose, I decided to rework my transmitting mechanism by combining
two examples from the
https://www.boost.org/doc/libs/1_66_0/libs/beast/example/doc/http_examples.hpp.
The mentioned examples are the "Example: Incremental Read" and the "Example:
Send Child Process Output".
This example (that follows) partly works, but it has some issues.
Very often, when I have a series of requests to execute on one connection, I
failed to read the second or the third response (the header) to a successfully
written request, and therefore the connection gets broken, and the client
(browser) reconnects and tries to execute them in a different session. This
makes traffic very slow and annoying.
Although the proxy app is written as async one, this method is written in a
synced (blocking) manner and serves only to receive the response from the host
(upstream) in chunks and write the received data chunks directly as they are
received to the original client (downstream).
The question is what is it that I am doing wrong?
I believe an experienced beast boost user could pick up the problem from reading the example.
std::shared_ptr<beast::ssl_stream<beast::tcp_stream>> m_sslDownStream;
std::shared_ptr<beast::ssl_stream<beast::tcp_stream>> m_sslUpStream;
beast::flat_buffer m_upBuffer;
void Session::do_read_upstream_buffered_response()
{
beast::error_code ec;
size_t bytes_transferred = 0
beast::flat_buffer m_upBuffer;
http::response_parser<http::buffer_body> resPar;
resPar.body_limit(ULONG_MAX);
bytes_transferred = http::read_header(*m_sslUpStream.get(), m_upBuffer, resPar, ec);
if (ec)
{
return fail(ec, "read header");
}
http::response<http::buffer_body> bufRes;
bufRes.result(resPar.get().result_int());
bufRes.version(resPar.get().version());
int field_count = 0;
for (auto const& field : resPar.get())
{
bufRes.insert(field.name_string().to_string(), field.value().to_string());
}
// No data yet, but we set more = true to indicate
// that it might be coming later. Otherwise the
// serializer::is_done would return true right after
// sending the header.
bufRes.body().data = nullptr;
bufRes.body().more = true;
http::response_serializer<http::buffer_body, http::fields> resSer { bufRes };
bytes_transferred = http::write_header(*(m_sslDownStream.get()), resSer, ec);
if (ec)
{
LSPROXY_LOGD(LOG_MITM_PROXY, "Session[%d]::do_read_upstream_buffered_response(%s) Failed to write header to the original client (downstream) with error: %s", this, m_sessionStateStr, ec.message().c_str());
return fail(ec, "write header");
}
// Read the rest of the response body upstream and send it downstream
while (!resPar.is_done())
{
char buf[8192];
resPar.get().body().data = buf;
resPar.get().body().size = sizeof(buf);
bytes_transferred = http::read(*m_sslUpStream.get(), m_upBuffer, resPar, ec);
if (ec == http::error::need_buffer)
{
ec.message().c_str());
ec.assign(0, ec.category());
}
if (ec)
{
return fail(ec, "read body");
}
// Point to our buffer with the bytes that
// we received, and indicate that there may
// be some more data coming
bufRes.body().data = buf;
bufRes.body().size = sizeof(buf) - resPar.get().body().size;
bufRes.body().more = true;
bytes_transferred = http::write(*(m_sslDownStream.get()), resSer, ec);
// This error is returned by body_buffer during
// serialization when it is done sending the data
// provided and needs another buffer.
if (ec == http::error::need_buffer)
{
ec.message().c_str());
ec = {};
//continue;
}
if (ec)
{
return fail(ec, "write body");
}
} //while (!resPar.is_done())
// `nullptr` indicates there is no buffer
bufRes.body().data = nullptr;
// `false` means no more data is coming
bufRes.body().more = false;
// Send the response header to the original client (downstream).
bytes_transferred = http::write(*(m_sslDownStream.get()), resSer, ec);
// Read another request from the original client (downstream)
do_read_downstream();
}
Just for the sake of others having the same or similar problem, I'd like to post the resolution to my problem.
The answer was in the question all along.
To be more precise in the https://www.boost.org/doc/libs/1_66_0/libs/beast/example/doc/http_examples.hpp there is an Example: HTTP Relay wich is exaclty what I needed in the first place.
Theere are small differences in this example from what I have combined my self from the two other examples (mentioned in the original post).
The most important one, the Example: HTTP Relay doesn't use a buffered body response:
http::response<http::buffer_body> bufRes;
to construct the serializer with:
http::response_serializer<http::buffer_body, http::fields> resSer { bufRes };
it uses the receiving parser directly to construct the serializer with:
// Create a parser with a buffer body to read from the input.
parser<isRequest, buffer_body> p;
// Create a serializer from the message contained in the parser.
serializer<isRequest, buffer_body, fields> sr{p.get()};
With a little adaptation, the Example: HTTP Relay works just fine for my proxy all types of requests, small body requsts, but also with big files downloading and data streams as well.
I' trying to send html through sockets in c++; after accept the request, my code will call the following function to send arr to client. When I test it on terminal with code of client in c, I received arr. However ,when I tried to connect to port through a web browser, my code shown connect success and send success, but nothing is printed out on browser, it just keep loading. why is that?
void sendTCP(int client_socket, vector<string> path)
{
cout<<"in sendTCP\n";
//string web=conWeb(path);
//cout<<"constructed web is "<<web<<endl;
char arr[1024]="HTTP/1.1 200 OK\r\n\r\n<html>\n\r<body>\n\r\rhello\n\r</body>\n</html>";
int send_res=send(client_socket,arr,sizeof(arr),0);
if(send_res == -1)
{
perror("send");
}
else{
cout<<"send success\n";
}
}
This worked:
char arr[200]="HTTP/1.1 200 OK\nContent-Type:text/html\nContent-Length: 16\n\n<h1>testing</h1>";
int send_res=send(sock,arr,sizeof(arr),0);
Maybe try restructuring the string
arr="HTTP/1.1 200 OK\nContent-Type:text/html\nContent-Length: 16\n\n<h1>testing</h1>"
I have a problem with websocket connection to wss://www.bitmex.com/realtime.
I found an axample in this question: Connect Websocket with Poco libraries , but I can't do the same with my wss:// address.
HTTPClientSession cs("wss://www.bitmex.com", 443);
HTTPRequest request(HTTPRequest::HTTP_CONNECT, "/realtime", HTTPMessage::HTTP_1_1);
request.set("origin", "wss://www.bitmex.com");
HTTPResponse response;
try {
WebSocket* m_psock = new WebSocket(cs, request, response);
//some code
}
catch (std::exception &e) {
std::cout << "Exception " << e.what();
}
I'm always receiving the exception: "Host not found" after string
WebSocket* m_psock = new WebSocket(cs, request, response);
HTTPClientSession takes a host string as the first param but you have given a host string with a protocol on the front.
The samples have a WebSocketServer in Net but sometimes you need to look at the test suite to find more details and it does require a little more work.
See WebSocketTest.cpp for a basic test that uses a WebSocket.
I am using Poco to send HTTP requests, as the name implies. Right now, I'm just trying to send a GET request to google.com and store the resulting HTML in a string to test out Poco and see if it fits what I need. However, I'm having a little trouble with this. Here's my code:
try
{
Poco::URI uri("https://www.google.com");
std::string path(uri.getPathAndQuery());
if (path.empty()) path = "/";
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort());
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1);
request.add("Content-Length", "0");
Poco::Net::HTTPResponse response;
doRequest(session, request, response);
}
catch (Poco::Exception& exc)
{
OutputDebugStringA(exc.displayText().c_str());
}
void doRequest(Poco::Net::HTTPSClientSession& session, Poco::Net::HTTPRequest& request, Poco::Net::HTTPResponse& response)
{
session.sendRequest(request);
std::istream& is = session.receiveResponse(response);
std::string body(std::istreambuf_iterator<char>(is), { });
message = (LPCWSTR)response.getStatus();
}
I have put breakpoints on every line of doRequest, but the only ones that are triggered are the first two. After clicking continue on the second, the program simply continues as normal. I'm not getting any exceptions or anything. I am adding Content-Length: 0 to avoid a NoMessageException from Poco.
a working post request with postman interface is not working when trying to implement in c++ with chilkat library, with postman I get response 200, with the program i get 401 (unauthorized).
I'm using chilkat's example for rest post request.
wherever you see username and password, valid values are filled.
CkRest rest;
// Make the initial connection (without sending a request yet).
bool bTls = true;
int port = 443;
bool bAutoReconnect = true;
success = rest.Connect("https://dev-182721.oktapreview.com",port,bTls,bAutoReconnect);
if (success != true) {
std::cout << rest.lastErrorText() << "\r\n";
return;
}
rest.put_Authorization("username:password");
rest.authorization();
rest.AddHeader("Content-Type","application/x-www-form-urlencoded");
// Provide query params.
rest.AddQueryParam("grant_type","password");
rest.AddQueryParam("redirect_uri","http://localhost");
rest.AddQueryParam("username","username");
rest.AddQueryParam("password","password");
rest.AddQueryParam("scope","openid");
const char *responseStr=
rest.fullRequestFormUrlEncoded("POST","/oauth2/default/v1/token");
if (rest.get_LastMethodSuccess() != true) {
std::cout << rest.lastErrorText() << "\r\n";
return;
}
// When successful, the response status code will equal 200.
can anyone please help me figure out what's missing
Okta access token examples are available here: https://www.example-code.com/cpp/okta_oauth_oidc.asp