GRPC not passing value when one service calls another service? - c++

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.

Related

Qt (6.3.1), C++ - How to send POST request over HTTPS

I'm trying to send a POST request to an HTTPS server (Jazz server) which expects a client certificate. In particular, this request concerns a login attempt to a Jazz server.
I'm using Qt 6.3.1 and my project is developed in C++.
I've tried many solutions but I couldn't get any response from the server: this is the result of QNetworkReply::error() function
Error: QNetworkReply::ProtocolInvalidOperationError - "Error transferring https://rtc.***.com/qm/authenticated/j_security_check - server replied: Bad Request"
One of my latest implementations is the following:
const static QString BASE_URL = "https://rtc.***.com/";
const static QString QM_AUTH_URL = "qm/authenticated/j_security_check";
void MainWindow::login(QString u, QString p) {
uname = u;
pwd = p;
netManager = new QNetworkAccessManager(this);
// Read the SSL certificate
QFile file("./myCert.cer");
if(!file.open(QIODevice::ReadOnly)) {
qDebug()<<"File opening error!";
return;
}
// Create a certificate object
const QSslCertificate certificate(file.readAll());
// Add this certificate to all SSL connections
QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
conf.addCaCertificate(certificate);
QSslConfiguration::setDefaultConfiguration(conf);
sslsock = new QSslSocket(this);
if(!sslsock->isOpen() || !sslsock->isEncrypted() || !sslsock->isValid()) {
connect(sslsock, &QSslSocket::sslErrors, this, &MainWindow::printSslErrors);
connect(sslsock, &QSslSocket::encrypted, this, &MainWindow::socketConnected);
sslsock->setLocalCertificate(certificate);
sslsock->setSslConfiguration(conf);
sslsock->connectToHostEncrypted("rtc.***.com", 443);
} else {
socketConnected();
}
void MainWindow::printSslErrors(const QList<QSslError> &err) { //never called
for(int i=0; i<err.size(); i++) {
qDebug()<<"Error "<<(i+1)<<": "<<err[i].error()<<" - "<<err[i].errorString();
}
sslsock->ignoreSslErrors(err);
}
void MainWindow::socketConnected() {
qDebug()<<"SSL handshake completed!";
qDebug()<<"sslsock->isEncrypted(): "<<sslsock->isEncrypted();
qDebug()<<"sslsock->isOpen(): "<<sslsock->isOpen();
qDebug()<<"sslsock->isReadable(): "<<sslsock->isReadable();
qDebug()<<"sslsock->isValid(): "<<sslsock->isValid();
qDebug()<<"sslsock->isWritable(): "<<sslsock->isWritable();
qDebug()<<sslsock->peerCertificate() << " cert";
netManager->setStrictTransportSecurityEnabled(true);
QUrlQuery params;
params.addQueryItem("j_username", uname);
params.addQueryItem("j_password", pwd);
QNetworkRequest req(QUrl(BASE_URL+QM_AUTH_URL));
QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
req.setSslConfiguration(conf);
req.setRawHeader("Accept", "application/xml");
req.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");
repl = netManager->post(req, params.query(QUrl::FullyEncoded).toUtf8());
connect(repl, &QNetworkReply::finished, this, &MainWindow::finishReading);
connect(repl, &QNetworkReply::sslErrors, this, &MainWindow::printSslErrors);
}
void MainWindow::readData() {
dataBuffer.clear();
dataBuffer.append(repl->readAll());
}
void MainWindow::finishReading() {
readData();
#if DEBUG
std::ofstream dataBuffFile, reqFile;
reqFile.open("request.txt", std::ios::out);
if(reqFile) {
reqFile<<"RawHeaderList size: "<<repl->request().rawHeaderList().size()<<std::endl;
for(int i=0; i<repl->request().rawHeaderList().size(); i++) {
reqFile<<repl->request().rawHeaderList().at(i).data()<<std::endl;
}
reqFile<<"Accept: "<<repl->request().rawHeader("Accept").data()<<std::endl;
reqFile<<"Content-Type: "<<repl->request().rawHeader("Content-Type").data()<<std::endl;
reqFile<<"Content-Length: "<<repl->request().rawHeader("Content-Length").data()<<std::endl;
reqFile<<"URL: "<<repl->request().url().toDisplayString().toStdString()<<std::endl;
reqFile.close();
} else {
qDebug()<<"Error in file opening!";
}
dataBuffFile.open("dataBuffer.txt", std::ios::out);
if(dataBuffFile) {
dataBuffFile<<dataBuffer.data();
dataBuffFile.close();
} else {
qDebug()<<"Error in file opening!";
}
#endif
if(repl->error() != QNetworkReply::NoError) {
qDebug()<<"Error: "<<repl->error()<<" - "<<repl->errorString();
warnMsg(this, "Error", QString("Request[Error] : %1").arg(repl->errorString()));
} else {
//TO_DO: CONVERT DATA
dataBuffer.clear();
}
}
SSL handshake is ok, I have no problems setting SSL configuration and using OpenSSL.
I simply can't login with the jazz server, which replies with "bad request".
I've tried also to make an HTTPS request to "www.google.com", but the outcome is -more or less- the same.
What is the methodology to be able to make HTTPS requests with Qt/C++?

rest post request with chilkat lib

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

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

node.js http couldn't receive request from C++ clients via socket

I am trying to send GET request to nodejs server from a C++ client.
nodejs server:
const server = http.createServer((request, response) => {
console.log(request.url);
response.end("received");
})
and here is my C++ clients:
while(getline(cin, random_input)) {
int s_len;
input = "GET / HTTP/1.1\r\n\r\n";
s_len = send(sock, input.c_str(), input.size(), 0);
if( s_len < 0)
{
perror("Send failed : ");
return false;
}
cout<<socket_c.receive(1024);
}
string tcp_client::receive(int size=512)
{
char buffer[size];
string reply;
int r_len; // received len
//Receive a reply from the server
r_len = recv(sock, buffer, sizeof(buffer), 0);
if( r_len < 0)
{
puts("recv failed");
}
if(buffer[r_len-1] == '\n') {
buffer[r_len-1] = '\0';
} else {
buffer[r_len] = '\0';
}
reply = buffer;
return reply;
}
so the C++ client can send GET requests each time when it's typing something in the terminal.
It works pretty fine if I type something right after the connection has been established. However, if I wait for 15-30 seconds after establish the connection, then type something on the client program, although the number of byte s_len that has been sent is correct, the server could't received anything.
May I know what goes wrong?
A few errors I spotted:
send return value is not checked correctly. Condition input.size() == s_len must be true.
recv return value is not checked of EOF. It treats r_len of 0 as valid data instead of disconnect. This may be the reason you do not see server replies: it may have disconnected but you did not notice that.
Setting the value of keepAliveTimeout of the node.js server to 0 could solve the problem

Mutual authentication always succeeds with OpenSSL

I am using openssl and zmq to write a server and a client.
My client and server need mutual authentication.
but after I set SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_FAIL_IF_NO_PEER_CERT,NULL) on server, the handshake always successes whether the client send the certificate or not.
In addition, SSL_get_peer_certificate(tls->get_ssl_()) return null and SSL_get_verify_result(tls->get_ssl_()) return 0 which means X509_V_OK.
I am really confused and desperate now. Any suggestions or corrections?
This is part of my code:
OpenSSL_add_all_algorithms();
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
const SSL_METHOD *meth;
SSL_CTX *ssl_ctx;
//**************************part of client************************
{
meth = SSLv23_client_method();
ssl_ctx = SSL_CTX_new(meth);
SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL);
int rc1 = SSL_CTX_load_verify_locations(ssl_ctx, ".\\demoCA\\private\\server_chain.pem",".\\demoCA\\private\\");///
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx,"pw");
std::string cert_chain(".\\demoCA\\private\\client_chain.pem");
std::string cert(".\\demoCA\\private\\client_crt.pem");
std::string key(".\\demoCA\\private\\client_key.pem");
int code = SSL_CTX_use_certificate_chain_file(ssl_ctx,cert_chain.c_str());
if (code != 1)
{
std::cout<<"error1\n";
//throw TLSException("failed to read credentials.");
}
code = SSL_CTX_use_PrivateKey_file(ssl_ctx,key.c_str(),SSL_FILETYPE_PEM);
i f (code != 1)
{
std::cout<<"error2\n";
//throw TLSException("failed to read credentials.");
}
if(!SSL_CTX_check_private_key(ssl_ctx))
{
std::cout<<"key wrong";
system("pause");
exit(0);
}
}
//*****************part of server****************************
{
meth = SSLv23_server_method();
ssl_ctx = SSL_CTX_new(meth);
SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_FAIL_IF_NO_PEER_CERT,NULL)
SSL_CTX_set_client_CA_list(ssl_ctx,SSL_load_client_CA_file(".\\demoCA\\private\\client_chain.pem"));//
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx,"pw");
std::string cert_chain(".\\demoCA\\private\\server_chain.pem");
std::string cert(".\\demoCA\\private\\server_crt.pem");
std::string key(".\\demoCA\\private\\server_key.pem");
int rc = SSL_CTX_use_certificate_file(ssl_ctx,cert.c_str(),SSL_FILETYPE_PEM);
if (rc!=1)
{
//throw TLSException("failed to read credentials.");
std::cout<<"error1\n";
}
rc = SSL_CTX_use_PrivateKey_file(ssl_ctx,key.c_str(),SSL_FILETYPE_PEM);
if (rc!=1)
{
//throw TLSException("failed to read credentials.");
std::cout<<"error2\n";
}
int rcode = SSL_CTX_check_private_key(ssl_ctx);
if(rcode!=1)
{
std::cout<<"key wrong";
system("pause");
//exit(0);
}
}
From the documentation of SSL_CTX_set_verify:
SSL_VERIFY_FAIL_IF_NO_PEER_CERT
Server mode: if the client did not return a certificate, the TLS/SSL handshake is immediately terminated with a "handshake failure" alert. This flag must be used together with SSL_VERIFY_PEER.
You did not use it together with SSL_VERIFY_PEER as described in the documentation and thus it has no effect.