encoding file as base64 string in QT with XMLRPC - qt

I am trying to send a file via xmlrpc as a base64 encoded string.
QFile sourceFile("/home/alexander/test.jpg");
QByteArray srcRawData = sourceFile.readAll();
QByteArray base64Encoded = srcRawData.toBase64();
std::string strTest(base64Encoded);
xmlrpc_c::paramList sampleAddParms;
sampleAddParms.add(xmlrpc_c::value_string("113957571"));
sampleAddParms.add(xmlrpc_c::value_string(strTest));
sampleAddParms.add(xmlrpc_c::value_string("test.jpg"));
When I send this to my server I get:
Client threw error: RPC response indicates failure. Bad parameter type (ap_adddocument): expected base64 for parameter data, got (Python) .
This is the class definition o xmlrpc_c::value_*
http://xmlrpcpp.sourceforge.net/doc/classXmlRpc_1_1XmlRpcValue.html
I just realized I need to use the xmlrpc_c::value_bytestring() instead. How do I convert a File into a bytestring in C++? I have a ByteArray already.
I am at a loss here..

Looking at your code, it seems that you can use xmlrpc_c::value_string()
Convert your base64 string in to a const char* and try. Following code should work. But still enough detail is not available in your question.
QFile sourceFile("/home/alexander/test.jpg");
QByteArray base64Encoded = sourceFile.readAll().toBase64();
const char* b64Enc = QString::fromLatin1(base64Encoded).toStdString().c_str();
xmlrpc_c::paramList sampleAddParms;
sampleAddParms.add(xmlrpc_c::value_string("113957571"));
sampleAddParms.add(xmlrpc_c::value_string(b64Enc));
sampleAddParms.add(xmlrpc_c::value_string("test.jpg"));

Related

What's the equivalent of nodejs Buffer.from(buffer, "base64") in deno

I'm working on a database with blob data. I made use of deno MySQL to pull the record and want to return it as a base64. In nodejs there's this Buffer.from(<buffer data>, "base64") then to print the base64 value do .toString().
How can I do this using Deno? I've been reading a lot about base64 encoder and some third-party libraries but I can't find anything.
// import mysqlClient from "https://deno.land//x/mysql#v2.10.2/mod.ts"
// mysql configuration :w
// some configuration to connect to mysql
const [{pdf}] = await mysql.query("select pdf from files where ...")
const b64 = atob(pdf); // Invalid Charater
console.log(typeof b64); // String
Tried using nodej and I just have to do Buffer.from(pdf, "base64").toString(); and it returns the correct base64 string
Was able to fix the problem. Seems like the problem was the MySQL plugin. I tried using mysql2 (https://deno.land/x/mysql2#v1.0.6) and it's returning the correct datatype and was able to convert data to base64 with the answers given below.
The Deno standard lib provides functions to encode / decode base64 :
import { decode as base64Decode, encode as base64Encode } from 'https://deno.land/std#0.166.0/encoding/base64.ts'
import { assertEquals } from 'https://deno.land/std#0.166.0/testing/asserts.ts'
const value = 'Hello World!'
console.log('value :', value)
const encodedValue = base64Encode(value)
console.log('encodedValue :', encodedValue)
const decodedValue = new TextDecoder().decode(base64Decode(encodedValue))
console.log('decodedValue :', decodedValue)
assertEquals(decodedValue, value)

Data send by Debugging

I've got a server, which ought to send image's QByteArray toBase64 format (attached in xml) to the client. Server itself works fine when I Run it, but when started Degubbing instead of just Running. The server doesn't send a image xml with appended QByteArray. I can not understand what is the reason for that? It shows no error while server started by Debugging, by the way. The image is on the server side and its server task to send an image. Here is how server extracts the image by method getVCardImage:
QByteArray &VCardExtensionPrivate::getVCardImage(const QString &imageName,
const QString& type)
{
if(!m_image.isNull()) m_image.clear();
QString imagePath = QString("%1/avatars/%2").arg(QCoreApplication::applicationDirPath())
.arg(imageName);
QImage image;
image.load(imagePath);
if(!image.isNull()) {
QBuffer buffer(&m_image);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, imageType(type.toUpper()));
}
return m_image;
}
And I do save QByteArray into xml:
QDomElement newNodeTag = doc.createElement(QString("BINVAL"));
QDomText newNodeText = doc.createTextNode(getVCardImage(m_imagePath, photoType).toBase64());
Sending through
server()->sendPacket(xml)` \\ xml is QDomElement with <BINVAL>
Start Run works fine!
<BINVAL>`QByteArray(toBase64) format`<\BINVAL>
Start Debugging
<BINVAL>`empty without any QByteArray`<\BINVAL>

Qt code comprehension

i'm struggling with a code snippet for days now, i was wondering if someone could help me understand this code snippet. i'm not asking for code whatsoever, just someone to explain to me this please : (a uri appear to be the complete url to a service)
void RestClient::_prepareRequest( QNetworkRequest& a_request, const QString& a_uri ){
QSslConfiguration config(QSslConfiguration::defaultConfiguration());
config.setProtocol(QSsl::SslV3);
config.setSslOption(QSsl::SslOptionDisableServerNameIndication, true);
a_request.setSslConfiguration(config);
a_request.setRawHeader("Accept", "application/xml");
a_request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
QByteArray l_api_key; l_api_key.append( toQString( m_api_key) );
QByteArray l_request_hash;
l_request_hash.append( toQString( _buildRequestHash( toStlString(a_uri) ) ) );
a_request.setRawHeader("EMApikey", l_api_key );
a_request.setRawHeader("EMRequestHash", l_request_hash );
a_request.setUrl( QUrl( a_uri ) );
}
So what you've got there is a function taking two parameters, a reference to a QNetworkRequest and a constant reference to a QString for the URI you wish to access. The next lines sets QSslConfiguration to get the default SSL configuration for Qt's network access, and stores it in config. It then sets some further QSsl options and then sets the a_request's SSL settings to be provided by the config you've just set.
Next up it sets some HTTP headers for the request, so these are reasonably standardised, so the Accept references what kind of information is acceptable for the response from the server which in this case is xml (Accept header documentation). The Content-type tells the receiving server what sort of data you're sending in the request body.
The final stage sets a non-standard HTTP header, which is for the application API access key, after that it sets the URL you originally passed and the function is complete. After that the QNetworkRequest can be used with QNetworkAccessManager to send a request to a server, with an API key encoded in, and you'll receive an XML response in return.

How to safely handle raw (file) data in Java?

An image gets corrupted while being retrieved (through HTTP) and then sent (through HTTP) to a database. Image's raw data is handled in String form.
The service sends a GET for an image file, receives response with the raw image data (response's body) and the Content-Type. Then, a PUT request is sent with the aforementioned request's body and Content-Type header. (The PUT request is constructed by providing the body in String) This PUT request is sent to a RESTful database (CouchDB), creating an attachment (for those unfamiliar with CouchDB an attachment acts like a static file).
Now I have the original image, which my service GETs and PUTs to a database, and this 'copy' of the original image, that I can now GET from the database. If I then `curl --head -v "[copy's url]" it has the Content-Type of the original image, but Content-Length has changed, went from 200kb to about 400kb. If I GET the 'copy' image with a browser, it is not rendered, whereas, the original renders fine. It is corrupted.
What might be the cause? My guess is that while handling the raw data as a string, my framework guesses the encoding wrong and corrupts it. I have not been able to confirm or deny this. How could I handle this raw data/request body in a safe manner, or how could I properly handle the encoding (if that proves to be the problem)?
Details: Play2 Framework's HTTP client, Scala. Below a test to reproduce:
"able to copy an image" in {
def waitFor[T](future:Future[T]):T = { // to bypass futures
Await.result(future, Duration(10000, "millis"))
}
val originalImageUrl = "http://laughingsquid.com/wp-content/uploads/grumpy-cat.jpg"
val couchdbUrl = "http://admin:admin#localhost:5984/testdb"
val getOriginal:ws.Response = waitFor(WS.url(originalImageUrl).get)
getOriginal.status mustEqual 200
val rawImage:String = getOriginal.body
val originalContentType = getOriginal.header("Content-Type").get
// need an empty doc to have something to attach the attachment to
val emptyDocUrl = couchdbUrl + "/empty_doc"
val putEmptyDoc:ws.Response = waitFor(WS.url(emptyDocUrl).put("{}"))
putEmptyDoc.status mustEqual 201
//uploading an attachment will require the doc's revision
val emptyDocRev = (putEmptyDoc.json \ "rev").as[String]
// create actual attachment/static file
val attachmentUrl = emptyDocUrl + "/0"
val putAttachment:ws.Response = waitFor(WS.url(attachmentUrl)
.withHeaders(("If-Match", emptyDocRev), ("Content-Type", originalContentType))
.put(rawImage))
putAttachment.status mustEqual 201
// retrieve attachment
val getAttachment:ws.Response = waitFor(WS.url(attachmentUrl).get)
getAttachment.status mustEqual 200
val attachmentContentType = getAttachment.header("Content-Type").get
originalContentType mustEqual attachmentContentType
val originalAndCopyMatch = getOriginal.body == getAttachment.body
originalAndCopyMatch aka "original matches copy" must beTrue // << false
}
Fails at the last 'must':
[error] x able to copy an image
[error] original matches copy is false (ApplicationSpec.scala:112)
The conversion to String is definitely going to cause problems. You need to work with the bytes as Daniel mentioned.
Looking at the source it looks like ws.Response is just a wrapper. If you get to the underlying class then there are some methods that may help you. On the Java side, someone made a commit on GitHub to expose more ways of getting the response data other than a String.
I'm not familiar with scala but something like this may work:
getOriginal.getAHCResponse.getResponseBodyAsBytes
// instead of getOriginal.body
WS.scala
https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/play/api/libs/ws/WS.scala
WS.java
Here you can see that Response has some new methods, getBodyAsStream() and asByteArray.
https://github.com/playframework/playframework/blob/master/framework/src/play-java/src/main/java/play/libs/WS.java

RInside: parseEvalQ 'Parse Error' causes each subsequent call to parseEvalQ to give a 'Parse Error' even if exception handled

My code, which tries to emulate an R shell via C++, allows a user to send R commands over a tcp connection which are then passed to the R instance through the RInside::parseEvalQ function, during runtime. I have to be able to handle badly formatted commands. Whenever a bad command is given as an argument to parseEvalQ I catch the runtime error thrown (looking at RInside.cpp my specific error is flagged with 'PARSE_ERROR' 'status' within the parseEval(const string&, SEXP) function), what() gives a "St9exception" exception.
I have two problems, the first more pressing than the second:
1a . After an initial Parse Error any subsequent call to parseEvalQ results in another Parse Error even if the argument is valid. Is the embedded R instance being corrupted in some way by the parse error?
1b . The RInside documentation recommends using Rcpp::Evaluator::run to handle R exceptions in C++ (which I suspect are being thrown somewhere within the R instance during the call to parseEval(const string&, SEXP), before it returns the error status 'PARSE_ERROR'). I have experimented trying to use this but can find no examples on the web of how to practically use Rcpp::Evaluator::run.
2 . In my program I re-route stdout and stderr (at C++ level) to the file descriptor of my tcp connection, any error messages from the RInside instance get sent to the console, however regular output does not. I send RInside the command 'sink(stderr(), type="output")' in an effort to re-route stdout to stderr (as stderr appears to be showing up in my console) but regular output is still not shown. 'print(command)' works but i'd like a cleaner way of passing stdout straight to the console as in a normal R shell.
Any help and/or thoughts would be much appreciated. A distilled version of my code is shown below:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using namespace std;
string request_cpp;
ostringstream oss;
int read(FILE* tcp_fd)
{
/* function to read input from FILE* into the 'request_cpp' string */
}
int write(FILE* tcp_fd, const string& response)
{
/* function to write a string to FILE* */
}
int main(int argc, char* argv[])
{
// create RInside object
RInside R(argc,argv);
//socket
int sd = socket(PF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(40650);
// set and accept connection on socket
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
bind(sd,(struct sockaddr*)&addr, sizeof(addr));
listen(sd,1);
int sd_i = accept(sd, 0, 0);
//re-route stdout and stderr to socket
close(1);
dup(sd_i);
close(2);
dup(sd_i);
// open read/write file descriptor to socket
FILE* fp = fdopen(sd_i,"r+");
// emulate R prompt
write(fp,"> ");
// (attempt to) redirect R's stdout to stderr
R.parseEvalQ("sink(stderr(),type=\"output\");");
// read from socket and pass commands to RInside
while( read(fp) )
{
try
{
// skip empty input
if(request_cpp == "")
{
write(fp, "> ");
continue;
}
else if(request_cpp == "q()")
{
break;
}
else
{
// clear string stream
oss.str("");
// wrap command in try
oss << "try(" << request_cpp << ");" << endl;
// send command
R.parseEvalQ(oss.str());
}
}
catch(exception e)
{
// print exception to console
write(fp, e.what());
}
write(fp, "> ");
}
fclose(fp);
close(sd_i);
exit(0);
}
I missed this weeks ago as you didn't use the 'r' tag.
Seems like you are re-implementing Simon's trusted rserver. Why not use that directly?
Otherwise, for Rcpp question, consider asking on our rcpp-devel list.

Resources