How can one use CURL to send a shell script as the POST body to Tornado? - shell

It is unclear to me how Tornado expects to parse body arguments for all content types. It makes sense for JSON, and maybe form data, but for other body content types it is unclear to me how to format the request with CURL to get it to work.
Question: How can one use CURL to send a shell script as the POST body to Tornado? What is the formatting for the body arguments?
What I've tried:
curl -X POST -H "Content-Type: application/x-sh" http://localhost:8888/ -d script='#!/bin/bash \necho "scale=500\; 4*a(1)" | bc -l'
What I would hope or expect this to do is for Tornado to process the HTTP body so that (1) the body argument is script, and (2) the value corresponding to it is the shell script to compute pi:
#!/bin/bash
echo "scale=500\; 4*a(1)" | bc -l
Instead I just get a 400: Bad Request error, and my debugging logs show that the value of self.request.body_arguments is an empty dictionary {}.

You're sending POST data with this header - Content-Type: application/x-sh. But Tornado only supports application/x-www-form-urlencoded to parse submitted form/POST data.
Just submit the data with Content-Type: application/x-www-form-urlencoded and Tornado will make the submitted data available in body_arguments.

Related

ecobee API thermostat request (json) using bash and curl

I'm writing a bash script to interface with my ecobee (query info and change settings). I have the authorization all worked out (access token and refresh token) and am now trying to request info from the ecobee. This json parameter list is dynamically created. None of the curl examples in the Developers API Doc seem to work.
I've tried assigning the json to a variable (?json="$selection") and to a file (?json=#"$location"). My latest attempt (hard coding the json and escaping the braces) of the curl is as follows:
response=$(curl -s "https://api.ecobee.com/1/thermostat?json=\{"selection":\{"selectionType":"registered","selectionMatch":null,"includeRuntime":true,"includeSettings":true/}/}" -H "Content-Type: application/json;charset=UTF-8" -H "Authorization: Bearer $access_token")
and I received a null response declare -- response=""
If I have curl read from a file:
{"selection":{"selectionType":"registered","selectionMatch":null,"includeRuntime":true,"includeSettings":true}}
then I receive:
response='{
"status": {
"code": 4,
"message": "Serialization error. Malformed json. Check your request and parameters are valid."
}
}'
Which I assuming it' an escape issue?
Can anyone offer any insight? Again, I thought this would be the easy part. I'm using jq to build my request json. Other alternatives to curl that can better deal with json? I'm limited to bash (which is what I know)
Thanks
To integrate (arbitrary) data into a URL (or URI in general) you need to prepare it using percent-encoding first.
As you have mentioned to use jq to compose that data, you could add #uri to your jq filter to perform the encoding, and use the --raw-output (or -r) option to then output it properly.
For example, jq -r '#uri' applied to your JSON
{
"selection": {
"selectionType": "registered",
"selectionMatch": null,
"includeRuntime": true,
"includeSettings": true
}
}
would output
%7B%22selection%22%3A%7B%22selectionType%22%3A%22registered%22%2C%22selectionMatch%22%3Anull%2C%22includeRuntime%22%3Atrue%2C%22includeSettings%22%3Atrue%7D%7D
which you can use within the query string ?json=….

From Ruby to Perl, Post data is disappearing

I'm trying to mimic the following curl command that works perfectly:
curl -k -i -d #content.json -H "Content-Type: application/json" -H "Accept: applicaztion/json" https://localhost:909/api/authenticateUser
I'm mimicking the curl command in Ruby/rails. I'm using the rest-client gem. The target is an API written in old-style Perl. The problem is that the API does NOT "see" the payload that is sent in the new ruby code:
pload = '<string>'.to_json
response = RestClient::Request.execute(url: 'https://localhost:909/api/authenticateUser', method: :post, payload: pload, accept: :json, content_type: :json, verify_ssl: false)
What is going wrong? Is my Ruby code bad or is the Perl code "too stupid/old" to pick up the payload from ruby. This is the Perl code:
my $data = $cgi->param('POSTDATA') || "";
I tend to think the problem is with my ruby code since the old Perl code receives the payload properly from the curl command above and from some other old Perl code.
Thanks for the help.
For POSTDATA to be populated,
The request must have a Content-Length header
The value of the request's Content-Length header must be non-zero.
The request method must be POST.
The request must have a Content-Type header.
The value of the request's Content-Type header must not include any of the following:
application/x-www-form-urlencoded
multipart/form-data
application/xml
multipart/related

Ruby JSON.parse error

I am building a script that uses a cURL command against an API. I send the cURL command formatted as an application/json request and get the result, which I parse into a Ruby hash.
This works great when I use cURL POST commands, getting the correctly formatted JSON responses. However, when using cURL GET commands I am returned a JSON document that has headers:
puts r:
HTTP/1.1 200 OK
X-Compute-Request-Id: req-7e625990-068b-47d1-8c42-9d3dd3b27050
Content-Type: application/json
Content-Length: 1209
Date: Wed, 16 Jan 2013 20:47:41 GMT
{ <JSON DATA> }
When I try and do a JSON.parse(r) I get an unexpected token error at 'HTTP/1.1.'.
My method for this:
def list_flavors
r = %x(curl -s -k -D - -H \"X-Auth-Token: #{$token}\" -X 'GET' http://10.30.1.49:8774/v2/27e60c130c7748f48b0e3e9175702c30/flavors -H 'Content-type: application/json')
response = JSON.parse(r)
response
end
Is there a way to use regular expressions to pull the body out of the JSON doc and then parse?
Or am I going about this the wrong way when getting the response from cURL?
You'll need to find a way to cut out that header before passing the string into JSON.parse. JSON.parse expects valid json only.
Rather than curling and using the thing wholesale as a string, I'd suggest you use the very versatile ruby Net::HTTP and/or OpenURI libraries, which will allow you to easily access just your response's body without the header.

Bash curl POST a binary variable

How do you POST a binary variable in curl bash?
#!/usr/bin/env bash
IMAGE=$(curl "http://www.google.com/images/srpr/logo3w.png")
curl --data-binary "$IMAGE" --request "POST" "http://www.somesite.com"
Curl seems to do corrupt the image when uploading.
Curl has the option to write response to disk and then read from it, but it'd be more efficient to do it solely in memory.
Try to eliminate the variable ... as follows:
curl "http://www.google.com/images/srpr/logo3w.png" | curl --data-binary - --request "POST" "http://www.somesite.com"
From the curl man page:
If you start the data with the letter #, the rest should be a file name to read the data from, or - if you want curl to read the data from stdin.
EDIT: From the man page, too:
--raw When used, it disables all internal HTTP decoding of content or transfer encodings and instead makes them passed on unaltered, raw. (Added in 7.16.2)
What happens, if applied on either or both sides?
I had a related problem, where I wanted to dynamically curl a file from a given folder.
curl --data-binary directory/$file --request "POST" "http://www.somesite.com"
did not work - uploaded the string "directory/myFile.jar" instead of the actual file.
Adding the # symbol
curl --data-binary #directory/$file --request "POST" "http://www.somesite.com" fixed it.

How do I execute an HTTP PUT in bash?

I'm sending requests to a third-party API. It says I must send an HTTP PUT to http://example.com/project?id=projectId
I tried doing this with PHP curl, but I'm not getting a response from the server. Maybe something is wrong with my code because I've never used PUT before. Is there a way for me to execute an HTTP PUT from bash command line? If so, what is the command?
With curl it would be something like
curl --request PUT --header "Content-Length: 0" http://website.com/project?id=1
but like Mattias said you'd probably want some data in the body as well so you'd want the content-type and the data as well (plus content-length would be larger)
If you really want to only use bash it actually has some networking support.
echo -e "PUT /project?id=123 HTTP/1.1\r\nHost: website.com\r\n\r\n" > \
/dev/tcp/website.com/80
But I guess you also want to send some data in the body?
Like Mattias suggested, Bash can do the job without further tools. If you want to send data, you have to preset at least "Content-length". With variables "host", "port", "resource" and "data" defined, you can do a HTTP put with
echo -e "PUT /$resource HTTP/1.1\r\nHost: $host:$port\r\nContent-Length: ${#data}\r\n\r\n$data\r\n" > /dev/tcp/$host/$port
I tested this with a Rest API and it workes fine.

Resources