Nested JSON not working as expected with HTTPie in Zsh - zsh

I can't figure out why sending nested JSON with HTTPie doesn't work as expected in Zsh. It looks like Zsh is trying to match bracket contents by default, but turning off matching (via noglob, nomatch, etc options) doesn't seem to work, and Httpie forms the literal foo[bar] instead of nesting the object:
> http --offline -v POST :/someurl foo[bar]=baz
zsh: no matches found: foo[bar]=baz
> noglob http --offline -v POST :/someurl foo[bar]=baz
POST /someurl HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 19
Content-Type: application/json
Host: localhost
User-Agent: HTTPie/2.6.0
{
"foo[bar]": "baz"
}
I'm using Httpie 3.0.2, and the same operation works as expected in Bash. I.e.:
{
"foo": {
"bar": "baz"
}
}

[...] is a globbing operator in most shells including zsh and needs to be quoted.
You'd have problems in other shells as well if there were some files in the current directory whose name matched that foo[bar]=baz glob pattern (try in bash/dash/ksh... after touch foob=bar fooa=bar for instance).
In bash and other POSIX shells, if no such file exist, the glob is passed literally by default, though the failglob and nullglob options can affect it.
Here, you need:
http --offline -v POST :/someurl 'foo[bar]=baz'

Related

Unsupported media type was attempted to be imported as a module

I used denodb Lib from this link "https://deno.land/x/denodb#v1.0.23/mod.ts" then I got the below Error:
error: Import 'https://raw.githubusercontent.com/denjucks/dex/master/mod.ts' failed: 404 Not Found
at https://deno.land/x/denodb#v1.0.23/deps.ts:3:0
That because the DEX library moved from this link "https://raw.githubusercontent.com/denjucks/dex/master/mod.ts".
So I tried this solution link (they forked denodb and changed the dex url in deps.ts ).
After that I got the below Error:
error: An unsupported media type was attempted to be imported as a module.
Specifier: https://github.com/takxlz/denodb/blob/master/mod.ts
MediaType: Unknown
Any idea how to solve this Error? (Also I tried clean cache but still same error happen)
Thanks.
https://github.com/takxlz/denodb/blob/master/mod.ts is actually a GitHub page (HTML page- text/html). The Deno modules which are imported are either text/plain or application/typescript. So use the raw version of the file uploaded on GitHub-
import * as Denodb from "https://raw.githubusercontent.com/takxlz/denodb/master/mod.ts";
curl -I "https://github.com/takxlz/denodb/blob/master/mod.ts"
# - content-type: text/html; charset=utf-8
curl -I "https://raw.githubusercontent.com/takxlz/denodb/master/mod.ts"
# - content-type: text/plain; charset=utf-8
curl -I "https://deno.land/x/denodb#v1.0.23/mod.ts"
# - content-type: application/typescript; charset=utf-8

Server utility: receive HTTPS POST requests, cat the data

To test something, I want to run a simple web server that:
Will listen for HTTPS POST requests
Print the POST data received to STDOUT (along with other stuff, potentially, so it's fine if it just cats the whole HTTP request)
Is there a quick way to set something like this up? I've tried using OpenSSL's s_server, but it only seems to want to respond to GET requests.
Since s_server does not support POST requests, you should use socat instead of openssl s_server:
# socat -v OPENSSL-LISTEN:443,cert=mycert.pem,key=key.pem,verify=0,fork 'SYSTEM:/bin/echo HTTP/1.1 200 OK;/bin/echo;/bin/echo this-is-the-content-of-the-http-answer'
Here are essential parameters:
fork: to loop for many requests
-v: to display the POST data (and other stuff) to STDOUT
verify=0: do not ask for mutual authentication
Now, here is an example:
We use the following POST request:
% wget -O - --post-data=abcdef --no-check-certificate https://localhost/
[...]
this-is-the-content-of-the-http-answer
We see the following socat output:
# socat -v OPENSSL-LISTEN:443,cert=mycert.crt,key=key.pem,verify=0,fork 'SYSTEM:/bin/echo HTTP/1.1 200 OK;/bin/echo;/bin/echo this-is-the-content-of-the-http-answer'
> 2017/08/05 03:13:04.346890 length=212 from=0 to=211
POST / HTTP/1.1\r
User-Agent: Wget/1.19.1 (freebsd10.3)\r
Accept: */*\r
Accept-Encoding: identity\r
Host: localhost:443\r
Connection: Keep-Alive\r
Content-Type: application/x-www-form-urlencoded\r
Content-Length: 6\r
\r
< 2017/08/05 03:13:04.350299 length=16 from=0 to=15
HTTP/1.1 200 OK
> 2017/08/05 03:13:04.350516 length=6 from=212 to=217
abcdef< 2017/08/05 03:13:04.351549 length=1 from=16 to=16
< 2017/08/05 03:13:04.353019 length=39 from=17 to=55
this-is-the-content-of-the-http-answer

curl uses POST for all requests after redirect

According to the documentation and some similar questions on SO curl should follow a redirect using GET method, unless --post30x is specified as a parameter. However that's the result of my testing
curl -kvv -b /tmp/tmp.BEo6w3GKDq -c /tmp/tmp.BEo6w3GKDq -X POST -H "Accept: application/json" -L https://localhost/api/v1/resource
> POST /api/v1/resource HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost
> Cookie: JSESSIONIDSSO=AB59F2FD09D38EDBAACB726CF212EA2E; JSESSIONID=743FD68B520840094B6D283A81CF3CFA
> Accept: application/json
>
< HTTP/1.1 302 Found
< Server: Apache-Coyote/1.1
< Strict-Transport-Security: max-age=15768000; includeSubDomains
< Cache-control: no-cache, no-store
< Pragma: no-cache
< Location: https://testserver.int/api/v1/resource
< Content-Length: 0
< Date: Fri, 27 Jan 2017 08:41:05 GMT
<
> POST /api/v1/resource HTTP/1.1
> User-Agent: curl/7.29.0
> Host: testserver.int
> Cookie: JSESSIONID=1tcxpkul4qyqh1hycpf9insei9
> Accept: application/json
I would expect the second request to actually be using GET instead of POST.
curl's man page says:
When curl follows a redirect and the request is not a plain GET (for
example POST or PUT), it will do the following request with a GET if
the HTTP response was 301, 302, or 303. If the response code was any
other 3xx code, curl will re-send the following request using the same
unmodified method.
You can tell curl to not change the non-GET request method to GET
after a 30x response by using the dedicated options for that:
--post301, --post302 and --post303.
Unfortunatelly that's not what I'm seeing and there is no option for --get30x.
So my question is - how to make curl follow a redirect response (301/302/303) with a GET request to the Location as it is written in the documentation?
I've tested it with curl/7.29.0 as well as curl/7.50.3.
Problem: You are telling curl to do that with your use of -X POST. As the man page section for -X explains this:
The method string you set with -X, --request will be used for all requests, which
if you for example use -L, --location may cause unintended side-effects when curl
doesn't change request method according to the HTTP 30x response codes - and
similar.
Fix: Remove the -X POST from your command line. Use -d "" instead to send an empty post that will adjust accordingly to the proper method after redirect.
More: Explanation and rant in my blog post unnecessary use of curl -X.

HTTP language representation

In the HTTP language, the following lines expresses a GET request on a collection of articles:
GET /articles HTTP/1.1
Accept: application/json; level=1
Host: example.com
However, in this language, how can we express a request through a POST with its data? Is there an official spec? Thank you.
Edit
Using curl, a such request could be:
curl -H 'Accept: application/json; level=1' \
-X POST \
-d '<json>' \
http://example.com/articles
...where <json> could be:
{
"article": {
"title": "foo"
}
}
This example can be a POST with an empty body since your request is composed only of HTTP headers. But I don't recommend this.
You can read about HTTP in the RFC

Compojure: getting the body from a POST request from which the Content-Type header was missing

Given this snippet:
(defroutes main-routes
(POST "/input/:controller" request
(let [buff (ByteArrayOutputStream.)]
(copy (request :body) buff)
;; --- snip
The value of buff will be a non-empty byte array iff there's the Content-Type header in the request. The value can be nonsencial, the header just has to be there.
However, I need to dump the body (hm... that came out wrong) if the request came without a content type, so that the client can track down the offending upload. (The uploading software is not under my control and its maintainers won't provide anything extra in the headers.)
Thank you for any ideas on how to solve or work around this!
EDIT:
Here are the headers I get from the client:
{
"content-length" "159",
"accept" "*/*",
"host" (snip),
"user-agent" (snip)
}
Plus, I discovered that Ring, using an instance of Java's ServletRequest, fills in the content type with the standard default, x-www-form-urlencoded. I'm now guessing that HTTPParser, which supplies the body through HTTPParser#Input, can't parse it correctly.
I face the same issue. It's definitely one of the middleware not being able to parse the body correctly and transforming :body. The main issue is that the Content-Type suggest the body should be parsable.
Using ngrep, I found out how curl confuses the middleware. The following, while intuitive (or rather sexy) on the command line sends a wrong Content-Type which confuses the middleware:
curl -nd "Unknown error" http://localhost:3000/event/error
T 127.0.0.1:44440 -> 127.0.0.1:3000 [AP]
POST /event/error HTTP/1.1.
Authorization: Basic SzM5Mjg6ODc2NXJkZmdoam5idmNkOQ==.
User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3.
Host: localhost:3000.
Accept: */*.
Content-Length: 13.
Content-Type: application/x-www-form-urlencoded.
.
Unknown error
The following however forces the Content-Type to being opaque and the middleware will not interfere with the :body.
curl -nd "Unknown error" -H "Content-Type: application/data" http://localhost:3000/event/error
T 127.0.0.1:44441 -> 127.0.0.1:3000 [AP]
POST /event/error HTTP/1.1.
Authorization: Basic SzM5Mjg6ODc2NXJkZmdoam5idmNkOQ==.
User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3.
Host: localhost:3000.
Accept: */*.
Content-Type: application/data.
Content-Length: 13.
.
Unknown error
I'm considering replacing the middleware with a more liberal one because even though the request is wrong, I'd still like to be able to decide what to do with the body myself. It's a really weird choice to zero the request body when the request doesn't make sense. I actually think a more correct behavior would be to pass it to an error handler which by default would return a 400 Bad Request or 406 Not Acceptable.
Any thoughts on that? In my case I might propose a patch to Compojure.
According to:
http://mmcgrana.github.com/ring/ring.middleware.content-type-api.html
the default content type is application/octet-stream. Unless you actively support that content type, can't you just check if the content type matches that one, and then dump whatever you need based on that?

Resources