c++ run curl in shell via system - c++

If I write this in my shell, everything works like a charme:
// shell (unix)
curl -X PUT -d "{ \"string\" : \"my string 1212 \"}" "https://my.firebaseio.com/myVal.json"
As you can tell, this inserts some stuff in my firebase. As mentioned above, this works as expected. Since I am not too deep in C++, I have no idea on how to PUT curl-requests internally. I was thinking about doing it in the shell via system.
I ended up with this:
// c++ code
system('curl -X PUT -d "{ \"string\" : \"my string 1212 \"}" "https://my.firebaseio.com/myVal.json" ');
This however produces this output:
curl: (6) Could not resolve host:
curl: (6) Could not resolve host: CD
curl: (7) Could not resolve host: CD
curl: (3) [globbing] unmatched close brace/bracket in column 1
Thanks for any helpful advices
// Update 1
After hearing that single quotes ' are reserved for chars and going for the solution erip provided, it is still the same output:
curl: (6) Could not resolve host:
curl: (6) Could not resolve host: cd
curl: (7) Could not resolve host: cd
curl: (3) [globbing] unmatched close brace/bracket in column 1
{
"error" : "Invalid data; couldn't parse JSON object, array, or value. Perhaps you're using invalid characters in your key names."
}

In C++, single quotes are used for the type char. Double quotes are reserved for std::strings or char *s.
Thus, your solution should be by simply replacing single quotes with double quotes and escaping the quotes that aren't your final quote:
system("curl -X PUT -d \"{ \"string\" : \"my string 1212 \"}\" https://my.firebaseio.com/myVal.json ");
However, like #DaoWen mentioned, always use a library if/when possible.
EDIT
I'd recommend trying this:
std::string command = "curl -X PUT -d \"{ \"string\" : \"my string 1212 \"}\" https://my.firebaseio.com/myVal.json ";
system(command.c_str());
But honestly, it's better to use fork and exec calls than system calls if you don't want to use libcurl.
EDIT 2
std::string command = "curl -H \"Content-Type: application/json\" -X PUT -d '{ \"string\" : \"my string 1212 \"}' https://my.firebaseio.com/myVal.json";
system(command.c_str());
The weird escaped quotes were treating key: "string" as the host because { was surrounded by quotes, acting as the data. I fixed this by surrounding the data to be passed with a single quote.
You can see that I PUT { "Hello" : "World!" } to your app here.
Hope this helped.

Related

How can I pass args to a curl request executed via boost::process:child?

I'm able to execute a http POST request using curl via boost::process::child by passing the entire command line. However, I would like to pass the arguments via boost::process::args but I cannot get it work.
This works:
const std::string cmdDiscord = "curl -X POST https://discord.com:443/api/webhooks/1234567890 -H \"content-type: application/json\" -d \"{\"content\": \"test\"}\"";
boost::process::child c(cmdDiscord); // this works
boost::process::child c(boost::process::cmd = cmdDiscord); // strangely, this doesn't work
I want to use boost::process::args but this fails:
std::vector<std::string> argsDiscord {"-X POST",
"https://discord.com:443/api/webhooks/1234567890",
"-H \"content-type: application/json\"",
"-d \"{\"content\": \"test\"}\""};
boost::process::child c(boost::process::search_path("curl"), boost::process::args (argsDiscord));
The error is curl: (55) Failed sending HTTP POST request which is quite a vague error message. I couldn't find any examples calling curl. Does anyone have any suggestions on getting this to work?
It should be
std::vector<std::string> argsDiscord {"-X", "POST",
"https://discord.com:443/api/webhooks/1234567890",
"-H", "content-type: application/json",
"-d", "{\"content\": \"test\"}"};
Since command interpretators pass arguments like -X POST are two arguments, not one.
The double quotes are a shell syntax as well. The shell interprets (removes) them during command line expansion.
Alternatively curl accepts adjacent values in short options (without space)
std::vector<std::string> argsDiscord {"-XPOST",
"https://discord.com:443/api/webhooks/1234567890",
"-H", "content-type: application/json",
"-d", "{\"content\": \"test\"}"};

Non-Latin characters are underscores under RESTful Google Translate API v2

I'm trying to use Google's translate method from its Translation API as documented here, but for some reason the translations I get replace non-Latin characters with underscores.
For instance, with curl on the command-line:
$ curl -X POST 'https://translation.googleapis.com/language/translate/v2/?source=en&target=de&q=Practicing+diligently+each+day+means+inevitable+improvement.&key=MY_API_KEY'
{
"data": {
"translations": [
{
"translatedText": "T_glich flei_ig zu _ben, bedeutet unausweichliche Verbesserung."
}
]
}
}
Compare to the English-to-German result from translate.google.com:
Täglich fleißig zu üben, bedeutet unausweichliche Verbesserung.
It's especially bad when the target is a language like Japanese, which doesn't contain Latin characters:
$ curl -X POST 'https://translation.googleapis.com/language/translate/v2/?source=en&target=ja&q=Practicing+diligently+each+day+means+inevitable+improvement.&key=MY_API_KEY'
{
"data": {
"translations": [
{
"translatedText": "______________________________________________________"
}
]
}
}
Maybe this is a trial account limitation? Nothing I've seen in this docs would indicate this, however.
I believe it's a string-encoding issue.
I assume your HTTP request body is being sent using application/x-www-form-urlencoded - which does not support characters above 0x7F (128) as literal text, see here: application/x-www-form-urlencoded and charset="utf-8"?
I suggest:
POST with an explicit Content-Type: application/json header with the charset=utf-8 field set. (x-www-form-urlencoded does not support the charset field).
Ensure your terminal is using UTF-8
Also take a look using a tool like Wireshark, or create the request in JavaScript using fetch and use Chrome's Developer Tools' Network tab's "Copy as cURL (Bash)" command to get the terminal command to use.
Somewhat embarrassingly, this was actually just an issue with tmux, the terminal multiplexer I was using to read the output of every call I made to the Translation API, both with curl and with the printed output of the code I was writing.
As per this Ask Ubuntu answer to someone else's tmux question, this is fixable by explicitly telling tmux to launch with UTF-8 support, i.e., tmux -u.
Thanks both to Dai and Daniel for pointing to a potential terminal issue.
I just tried with the following request and it worked well:
curl -X POST "https://translation.googleapis.com/language/translate/v2?key=MY_API_KEY" \
-H "Content-Type: application/json" \
--data "{
'q': 'Practicing diligently each day means inevitable improvement.',
'source': 'en',
'target': 'de'
}"
Giving this output:
{
"data": {
"translations": [
{
"translatedText": "Täglich fleißig zu üben, bedeutet unausweichliche Verbesserung."
}
]
}
}
And for the Japanese output:
{
"data": {
"translations": [
{
"translatedText": "毎日熱心に練習することは避けられない改善を意味します。"
}
]
}
}
Hope it helps

Varnishlog log only specified IP

I want to log varnish backend request which matches specified IP (for example 127.0.0.1).
So i have
"varnishlog -b -I BereqHeader:X-Forwarded-For: 127.0.0.1'"
Which actualy logs only the "BereqHeader:X-Forwarded-For:" part. I want to log full request, not only IP part.
That was first question, the second one is: how to disable loging empty request? I mean, if i have regex filter then i have a lot of request looking like this "* << BeReq >> 307454" and i obviously dont want to see them.
I have a solution. Log the data by
varnishlog -b -I BereqHeader:'X-Forwarded-For: 123.215.32.76' -i [other tags to log] > file.varnishlog
and then grep it by
cat file.varnishlog | grep -Pzo '* {3}<< BeReq {4}>>.\n- BereqHeader.+\n(-.\n)*'
which'll give us expected results.

Bash Script: sed/awk/regex to match an IP address and replace

I have a string in a bash script that contains a line of a log entry such as this:
Oct 24 12:37:45 10.224.0.2/10.224.0.2 14671: Oct 24 2012 12:37:44.583 BST: %SEC_LOGIN-4-LOGIN_FAILED: Login failed [user: root] [Source: 10.224.0.58] [localport: 22] [Reason: Login Authentication Failed] at 12:37:44 BST Wed Oct 24 2012
To clarify; the first IP listed there "10.224.0.2" was the machine the submitted this log entry, of a failed login attempt. Someone tried to log in, and failed, from the machine at the 2nd IP address in the log entry, "10.224.0.58".
I wish to replace the first occurrence of the IP address "10.224.0.2" with the host name of that machine, as you can see presently is is "IPADDRESS/IPADDRESS" which is useless having the same info twice. So here, I would like to grep (or similar) out the first IP and then pass it to something like the host command to get the reverse host and replace it in the log output.
I would like to repeat this for the 2nd IP "10.224.0.58". I would like to find this IP and also replace it with the host name.
It's not just those two specific IP address though, any IP address. So I want to search for 4 integers between 1 and 3, separated by 3 full stops '.'
Is regex the way forward here, or is that over complicating the issue?
Many thanks.
Replace a fixed IP address with a host name:
$ cat log | sed -r 's/10\.224\.0\.2/example.com/g'
Replace all IP addresses with a host name:
$ cat log | sed -r 's/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/example.com/g'
If you want to call an external program, it's easy to do that using Perl (just replace host with your lookup tool):
$ cat log | perl -pe 's/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/`host \1`/ge'
Hopefully this is enough to get you started.
There's variou ways to find th IP addresses, here's one. Just replace "printf '<<<%s>>>' " with "host" or whatever your command name is in this GNU awk script:
$ cat tst.awk
{
subIp = gensub(/\/.*$/,"","",$4)
srcIp = gensub(/.*\[Source: ([^]]+)\].*/,"\\1","")
"printf '<<<%s>>>' " subIp | getline subName
"printf '<<<%s>>>' " srcIp | getline srcName
gsub(subIp,subName)
gsub(srcIp,srcName)
print
}
$
$ gawk -f tst.awk file
Oct 24 12:37:45 <<<10.224.0.2>>>/<<<10.224.0.2>>> 14671: Oct 24 2012 12:37:44.583 BST: %SEC_LOGIN-4-LOGIN_FAILED: Login failed [user: root] [Source: <<<10.224.0.58>>>] [localport: 22] [Reason: Login Authentication Failed] at 12:37:44 BST Wed Oct 24 2012
googled this one line command together. but was unable to pass the founded ip address to the ssh command:
sed -n 's/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/\nip&\n/gp' test | grep ip | sed 's/ip//' | sort | uniq
the "test" is the file the sed command is searching for for the pattern

How can I send an automated reply to the sender and all recipients with Procmail?

I'd like to create a procmail recipe or Perl or shell script that will send an auto response to the original sender as well as anybody that was copied (either To: or cc:) on the original email.
Example:
bob#example.com writes an email to john#example.com and paul#example.com (in the To: field). Copies are sent via cc: to rob#example.com and alice#example.com.
I'd like the script to send an auto response to the original sender (bob#example.com) and everybody else that was sent a copy of the email (john#example.com, paul#example.com, rob#example.com and alice#example.com).
Thanks
You should be able to accomplish this using the this procmail module for Perl 5. You could also just use the procmail configuration files to do this as well.
Here's an example of our procmail configuration sending e-mails "through" a perl script.
:0fw
* < 500000
| /etc/smrsh/decode_subject.pl
I hope that helps get ya started.
FROM=`formail -rtzxTo:`
CC=`formail -zxTo: -zxCc: | tr '\n' ,`
:0c
| ( echo To: "$FROM"; echo Cc: "$CC"; echo Subject: auto-reply; \
echo; echo Please ignore. ) \
| $SENDMAIL -oi -t
A well-formed auto-reply should set some additional headers etc; but this should hopefully be enough to get you started. See also http://porkmail.org/era/mail/autoresponder-faq.html
Depending on you flavor of tr you might need to encode the newline differently; not all implementations of tr understand the '\n' format. Try with '\012' or a literal newline in single quotes if you cannot get this to work.