Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Properly using curl --data-urlencode when passing a variable

I'm trying to optimize my code and one particular piece of code is borrowed. I'd like to remove the sed so I'm not using any external processes in my main loop.

function sendMsg () {
value=$(echo $1 | sed 's/ /%20/g;s/!/%21/g;s/"/%22/g;s/#/%23/g;s/\&/%26/g;s/'\''/%28/g;s/(/%28/g;s/)/%29/g;s/:/%3A/g;s/\//%2F/g');
str="http://www.xxxx.com/api.ashx?v=1&k=$Key&a=send&w=$value";
curl -s $str;
}

I've edited this for clarity. The $value is simply to convert to a proper url for output via the curl command at the end of the function.

While this works just fine, I'm mostly interested in making this as fast to process as possible without forking to outside processes if I can.

Thanks for the comments so far!

Where I'm at so far is this:

function sendMsg () {
str="http://www.xxxx.com/api.ashx?v=1&k=$Key&a=send&w=";
curl -s $str --data-urlencode "$1";
}

Am I on the right track at least?

like image 981
yab Avatar asked Aug 12 '14 17:08

yab


People also ask

How to add URL-encoding to the URL in curl?

curl supports url-encoding internally with --data-urlencode: -G is also necessary to append the data to the URL. From curl doc: Note that the name part (msg in this case) is expected to be URL-encoded already. Also you can specify something like --request DELETE and it would indeed be a delete method instead of a GET.

How do I post data from a curl url?

Use curl --data-urlencode; from man curl: This posts data, similar to the other --data options with the exception that this performs URL-encoding. To be CGI-compliant, the <data> part should begin with a name followed by a separator and a content specification.

Does curl --data-urlencode -VV output send underscores to the server?

Added -vv output, --trace seemed to be just last line of -vv. Sorry about it. Running with --trace yourtracefile, in "yourtracefile" it appears that curl --data-urlencode does nothing to the underscores and sends them to the server.

Is there a way to URL-encode the name portion of a URL?

P.S., after name=content This will make curl URL-encode the content part and pass that on. Note that the name part is expected to be URL- encoded already. please add No, currently curl has no way to URL-encode the name portion. You will just have to do that yourself if really required.


2 Answers

First, the answer to your question: If you are doing a single substitution or filtering, using pattern matching is faster:

$ foo=${bar/old/new}               # Faster
$ foo=$(sed 's/old/new/' <<<$bar   # Slower

The first doesn't require spawning a sub-shell, and running sed, then substituting this back into $foo. However, if you are doing this almost a dozen times, I believe using sed may be faster:

value=$(sed -e 's/ /%20/g' \
   -e 's/!/%21/g' \
   -e 's/"/%22/g' \
   -e 's/#/%23/g' \
   -e 's/\&/%26/g' \
   -e 's/'\''/%28/g' \
   -e 's/(/%28/g' \
   -e 's/)/%29/g' \
   -e 's/:/%3A/g' \
   -e 's/\//%2F/g'<<<$1);

Note that this syntax is easier to read since each substitution command is on its own line. Also note that <<< eliminates the need to echo and pipe.

This only does a single call to sed while pattern matching has to be done multiple times.

However, you should be using --data and --data-uuencode instead of building the query string yourself:

$ curl -s http://www.xxxx.com/api.ashx \
    --data v=1 \
    --data k=$Key \
    --data a=send \
    --data-urlencode w="$value";

The --data--urlencode will encode the value of $value for you, so you don't have to do it. Unfortunately, this parameter doesn't exist in all versions of curl. It was added in version 7.18.0 back in January of 2008. Run curl --version to see what version you have:

$ curl --version     # Life is good
curl 7.30.0 (x86_64-apple-darwin13.0) libcurl/7.30.0 SecureTransport zlib/1.2.5

$ curl --version     # David Sad
curl 7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5

Addendum

In attempting this I'm getting an 'unsupported API versionERROR', even though my curl --version reports 7.29.0

I can't test what you have, but I decided to try our Jenkins server to see if I can set the build description. I made sure the description has spaces in it, so it requires --data-urlencoding. This command worked:

$ curl --user dweintraub:swordfish \
    --data Submit=Submit \
    --data-urlencode description="This is my test descripition" \
    http://jenkins.corpwad.com/jenkins/job/Admin-5.1.1/138/submitDescription

This is as if I did:

$ curl -user "dweintraub:swordfish http://jenkins.corpwad.com/jenkins/job/Admin-5.1.1/138/submitDescription?Submit=Submit&desciption=This%20is%20my%20test%20descripition"

Note that --data adds the question mark for you.

(No, swordfish isn't my password).

It's not as complex as your command, but it might help point out where you're having problems. Do you have a user name and password? If so, you need the --user parameter.

like image 110
David W. Avatar answered Oct 21 '22 11:10

David W.


If you have to do this a lot, the overhead of spawning multiple sed processes might add up. In that case, you can use the following lines instead:

value=${1// /%20/}
value=${value//!/%21}
value=${value//\"/%22}
value=${value//\#/%23}
value=${value//&/%26}
value=${value//\'/%27}
value=${value//(/%28}
value=${value//)/%29}
value=${value//:/%3A}
value=${value//\//%2F}
like image 44
chepner Avatar answered Oct 21 '22 11:10

chepner