rest post request with chilkat lib - c++

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

Related

GRPC not passing value when one service calls another service?

My grpc client code has 2 services, and it calls the Stat service from within the Delete service (and others not listed here), to populate the message properties before querying the server to delete it. The issue is, when I pass my path value from Stat to get_stat, it no longer exists. Just curious if there is a better way to structure my code to prevent this from happening? Very new to grpc and c++.
Client:
StatusCode DFSClientNodeP1::Stat(const std::string &filename, void *file_status)
{
Status return_status;
grpc::ClientContext context;
dfs_service::Empty request;
dfs_service::File_Metadata response;
if (file_status != NULL)
response = *(static_cast<dfs_service::File_Metadata *>(file_status));
response.set_filename(filename.c_str());
std::cout << "CLIENT: " << response.filename() << std::endl;
return_status = this->service_stub->get_status(&context, request, &response);
return return_status.error_code();
}
StatusCode DFSClientNodeP1::Delete(const std::string &filename)
{
StatusCode return_status;
grpc::ClientContext context;
dfs_service::File_Metadata request;
dfs_service::Empty response;
return_status = Stat(filename, &request);
if (return_status == 0)
{
return this->service_stub->delete_file(&context, request, &response).error_code();
}
else if (return_status == 5)
{
return return_status;
}
else
{
return StatusCode::CANCELLED;
}
}
Server:
Status get_status(ServerContext *context, const dfs_service::Empty *request, dfs_service::File_Metadata *response) override
{
std::cout << "SERVER: " << response->filename() << std::endl;
struct stat result;
if (stat(this->WrapPath(response->filename()).c_str(), &result) == 0)
{
response->set_filesize(result.st_size);
response->set_blocksize(result.st_blksize);
// metadata.set_creation_time(result.st_ctim);
response->set_modified_time(result.st_mtime);
return Status::OK;
}
else
{
return Status(StatusCode::NOT_FOUND, "File Not Found");
}
}
Output:
Client: TEST.jpg
Server:
In gRPC, the request message is sent from the client to the server, and the response message is sent from the server to the client. What you're doing here is sending an empty message from the client to the server. Your client code is setting the filename field in the response message before it gets the response from the server, but that entire message is getting overwritten by the actual server response.
What you need to do here is pass the filename as a field in the request message rather than making it a field in the response message.

hello world example for a mongoose webserver with SSL in C

I am trying to set a mongoose web server v3.3 with a self-signed SSL certificate. I know how to do it without SSL but I want to implement HTTPS.
I have implemented something like this:
void *event_handler(enum mg_event event,
struct mg_connection *conn) {
const struct mg_request_info *request_info = mg_get_request_info(conn);
static void* done = "done";
if (event == MG_NEW_REQUEST) {
if (strcmp(request_info->uri, "/hello") == 0) {
// handle c[renderer] request
if(strcmp(request_info->request_method, "GET") != 0) {
// send error (we only care about HTTP GET)
mg_printf(conn, "HTTP/1.1 %d Error (%s)\r\n\r\n%s",
500,
"we only care about HTTP GET",
"we only care about HTTP GET");
// return not null means we handled the request
return done;
}
// handle your GET request to /hello
char* content = "Hello World!";
char* mimeType = "text/plain";
int contentLength = strlen(content);
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Cache: no-cache\r\n"
"Content-Type: %s\r\n"
"Content-Length: %d\r\n"
"\r\n",
mimeType,
contentLength);
mg_write(conn, content, contentLength);
return done;
}
}
// in this example i only handle /hello
mg_printf(conn, "HTTP/1.1 %d Error (%s)\r\n\r\n%s",
500, /* This the error code you want to send back*/
"Invalid Request.",
"Invalid Request.");
return done;
}
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
return NULL;
}
int main(int argc, char **argv) {
const char *options[] = {
"ssl_certificate", "cert.pem",
"listening_ports", "443s",
"num_threads", "10",
NULL
};
static struct mg_context *ctx;
ctx = mg_start(&event_handler, options);
if(ctx == NULL) {
exit(EXIT_FAILURE);
}
puts("Server running, press enter to exit\n");
getchar();
mg_stop(ctx);
return EXIT_SUCCESS;
}
The problem is I am not able to access my server from the web browser. I think the problem is that the first event my callback receives is MG_INIT_SSL but I do not know how to handle or process it. Could anybody please help?
Firstly, I believe you should not have to handle other events than MG_NEW_REQUEST in your event handler.
I would also debug using openssl:
openssl s_client -connect <hostname:port>
to see that the SSL connection gets set up properly.
In any case, Cesanta does provide a complete working example for you to use:
https://github.com/cesanta/mongoose/tree/master/examples/simplest_web_server_ssl

sending a GET command to an ssl server to get result

I am trying to send a get request to acounts.google.com to be able to implement a library for C++ OAuth to learn it.
I get the following code from this post: Creating a HTTPS request using Boost Asio and OpenSSL and modified it as follow:
int main()
{
try
{
std::string request = "/o/oauth2/v2/auth";
boost::system::error_code ec;
using namespace boost::asio;
// what we need
io_service svc;
ssl::context ctx(svc, ssl::context::method::sslv23_client);
ssl::stream<ip::tcp::socket> ssock(svc, ctx);
ip::tcp::resolver resolver(svc);
auto it = resolver.resolve({ "accounts.google.com", "443" }); // https://accouts.google.com:443
boost::asio::connect(ssock.lowest_layer(), it);
ssock.handshake(ssl::stream_base::handshake_type::client);
// send request
std::string fullResuest = "GET " + request + " HTTP/1.1\r\n\r\n";
boost::asio::write(ssock, buffer(fullResuest));
// read response
std::string response;
do
{
char buf[1024];
size_t bytes_transferred = ssock.read_some(buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
std::cout << "Response received: '" << response << "'\n"; // I add this to see what I am getting from the server, so it should not be here.
} while (!ec);
// print and exit
std::cout << "Response received: '" << response << "'\n";
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
if (std::string const * extra = boost::get_error_info<my_tag_error_info>(e))
{
std::cout << *extra << std::endl;
}
}
}
The problem that I have is as follow:
1- The results that I am getting is not what I am getting when I visit https://accounts.google.com/o/oauth2/v2/auth using a web browser. I essentially getting a message that they can not find the requested URL /o/oauth2/v2/auth
<p>The requested URL <code>/o/oauth2/v2/auth</code> was not found on this server. <ins>ThatÔÇÖs all we know.</ins>
How should I setup the GET commend so I can get the same result that I am getting with a browser?
2- The application hangs getting data from server, apparently the following loop is not right:
do
{
char buf[1024];
size_t bytes_transferred = ssock.read_some(buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
} while (!ec);
What is the correct way of reading responce from the web server which is fast and read all data?
Edit 1
For reference based on accepted answer, I fixed the problem using the correct GET header as shown below:
// send request
std::string fullResuest = "GET " + request + " HTTP/1.1\r\n";
fullResuest+= "Host: " + server + "\r\n";
fullResuest += "Accept: */*\r\n";
fullResuest += "Connection: close\r\n\r\n";
boost::asio::write(ssock, buffer(fullResuest));
A HTTP/1.1 request must have a Host header. A simple experiment with OpenSSL will show the problem, i.e. the missing header:
$ openssl s_client -connect accounts.google.com:443
...
GET /o/oauth2/v2/auth HTTP/1.1
... The requested URL <code>/o/oauth2/v2/auth</code> was not found on this server. <ins>That’s all we know.</ins>
When adding the Host header instead we get a different response:
$ openssl s_client -connect accounts.google.com:443
...
GET /o/oauth2/v2/auth HTTP/1.1
Host: accounts.google.com
... >Required parameter is missing: response_type<
Apart from that HTTP/1.1 implicitly uses HTTP keep-alive, i.e. server and client might keep the connection open after the response is done. This means you should not read until the end of connection but should instead properly parse the HTTP header, extract the Content-length header and/or Transfer-Encoding header and behave according to their values. Or if you want it simpler use HTTP/1.0 instead.
For more information see the HTTP/1.1 standard.

Send Receive using casablanca c++ rest sdk

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'

Read Response of POCO HTTPClientRequest

Hi I am uploading a file using multipart upload in POCO (by sending a the content of file appended with boundaries through a normal POST request). But when I try to read the response as:
std::ostream& myOStream = session.sendRequest(req);
// sends the body
myOStream << reqBody;
Poco::Net::HTTPResponse res;
// get the response body from server
std::istream& inStream = session.receiveResponse(res);
std::ostringstream outStringStream;
outStringStream << inStream.rdbuf();
std::cout<< outStringStream.str();
I get this exception "SSL Connection Unexpectedly Closed" on this line:
outStringStream << inStream.rdbuf();
Also if i instead try to read the response as:
Poco::StreamCopier::copyStream( inStream, outStringStream );
std::cout<< outStringStream.str();
I get empty response (No exception in this case).
The server returns a plain text in response. And i am getting it as response if using qt, but not through POCO. Please help me to read the response body. What could be the reason of this exception??
Also, one more thing if I read the response status as res.getStatus() and res.getReason() it returns 200Ok. I dont understand what is the issue with response body.
This code is working for me you can try.
std::istream& rs = _httpClientSession.receiveResponse(response);
memset(_response, 0, RESPONSE_BUFF_SIZE);
rs.read(_response, RESPONSE_BUFF_SIZE-1);
//below code is just to clear the istream
std::streamsize nRead = rs.gcount();
while( !rs.eof() || nRead != 0)
{
rs.read(_response, RESPONSE_BUFF_SIZE);
nRead = rs.gcount();
}
One more thing, in case of any exception you have to reset http session by invoking _httpClientSession.reset();