This adds support for handling preflight requests in the REST API
and fixes currently mostly broken CORS.
Before we just let the user add custom response headers to the
configuration "headers" key but this is not the best way because
CORs headers and requests need special handling and doing it wrong
has security implications.
Therefore, I have added specific CORS-related configuration options
which control CORS behavour. We are forced to change the "headers"
defaults and will notify the users about this in the changelog.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
This changes the current strategy to extract headers from the IPFS daemon to
use them for hijacked endpoints in the proxy. The ipfs daemon is a bit of a
mess and what we were doing is not really reliable, specially when it comes to
setting CORS headers right (which we were not doing).
The new approach is:
* For every hijacked request, make an OPTIONS request to the same path, with
the given Origin, to the IPFS daemon and extract some CORS headers from
that. Use those in the hijacked response
* Avoid hijacking OPTIONS request, they should always go through so the IPFS
daemon controls all the CORS-preflight things as it wants.
* Similar to before, have a only-once-triggered request to extract other
interesting or custom headers from a fixed IPFS endpoint. This allows us to
have the proxy forward other custom headers and to catch
`Access-Control-Expose-Methods`. The difference is that the endpoint use for
this and the additional headers are configurable by the user (but with hidden
configuration options because this is quite exotic from regular usage).
Now the implementation:
* Replaced the standard Muxer with gorilla/mux (I have also taken the change
to update the gxed version to the latest tag). This gives us much better
matching control over routes and allows us to not handle OPTIONS requests.
* This allows also to remove the extractArgument code and have proper handlers
for the endpoints passing command arguments as the last segment of the URL. A
very simple handler that wraps the default ones can be used to extract the
argument from the url and put it in the query. Overall much cleaner this way.
* No longer capture interesting headers from any random proxied request. This
made things complicated with a wrapping handler. We will just trigger the one
request to do it when we need it.
* When preparing the headers for the hijacked responses:
* Trigger the OPTIONS request and figure out which CORS things we should set
* Set the additional headers (perhaps triggering a POST request to fetch them)
* Set our own headers.
* Moved all the headers stuff to a new headers.go file.
* Added configuration options (hidden by default) to:
* Customize the extract headers endpoint
* Customize what additional headers are extracted
* Use HTTPs when talking to the IPFS API
* I haven't tested this, but I did not want to have hardcoded 'http://' urls
around, as before.
* Added extra testing for this, and tested manually a lot comparing the
daemon original output with our hijacked endpoint outputs while looking
at the API traffic with ngrep and making sure the requets happen as expected.
Also tested with IPFS companion in FF and Chrome.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
tl;dr: this solves the user's immediate need and, even if not tne strictest
solution, it is the simplest one.
I think we should not have the server buffer output when we can do it rather
easily client side and have the clients use their own memory for the task even
if `stream-channels=false` would do this.
We can always change the approach, but this is the minimal solution to
json array with all the AddedOutput things.
We might not buffer at all and hack a `[`, `,` separating elements and `]`
at the end, when json encoding is enabled, etc. But that would not be clean,
specially if we mean to support more output formats at some point.
Enabling supporting stream-channels=false in the api/rest/client means adding
new methods, with tests, modifying the interface etc etc. for what is
essentially a presentation issue in "ctl" in the end. Similarly we could
buffer inside the client, but it is so trivial that I don't see advatange.
We should also start thinking about moving to streaming API endpoints and
when that moment arrives we shall revisit this discussion.
I have removed the hacky manual output parts by declaring a custom
addedOutputQuiet type which wraps added output and is understood by
the formatters.go helpers.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
Optimized filter to tracker status matching by using bitwise
comparisions
License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
Added a fail case where an invalid filter is passed in.
Update `api.rpcClient.Call` to `api.rpcClient.CallContext` and pass
in the Request context r.Context() so that context can be cancelled
when the request is cancelled by caller
Fixes#445
License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
Added filter option to `ipfs-cluster-ctl status`
When the --filter is passed, it will only fetch the peer information
where status of the pin matches with the filter value.
Valid filter values are tracker status types(i.e., "pinned",
"pin_error", "unpinning" etc), an alias of tracker status type (i.e.,
"queued" or "error"), comma separated list of tracker status type
and/or it aliases(i.e., "error,pinning")
On passing invalid filter value no status information will be shown
In particular, the filter would remove elements from []GlobalPinInfo
when none of the peers in GlobalPinInfo match the filter. If one peer
in the GlobalPinInfo matches the filter, the whole object is returned,
including the information for the other peers which may or not match it.
filter option works on statusAll("GET /pins"). For fetching pin status
for a CID("GET /pins/<cid>"), filter option would have no effect
Fixes#445
License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
-Fixed logic issue in match condition of 'filterStatus' function
-Added and verified success of test provided by @lanzafame
-Attempted to condense code and apply other cleanup provided by @lanzafame
License: MIT
Signed-off-by: Paul Jewell <sona1111@zoho.com>
Move ctl-health sharness tests to apprpriate file
Since the API is using the RPC mock to request metrics and it always
returns a mocked test metric we might just do c.Metrics("somemetricstype")
and check that there is no error. Here we just want to check that the
client is hitting an API endpoint (and understands the response).
Fixes#587
License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
Added API and client tests for GET /monitor/metrics/{metrics_type}
Fixes#587
License: MIT
Signed-off-by: Kishan Mohanbhai Sagathiya <kishansagathiya@gmail.com>
We should deprecate passing in Host/Port in the config,
but in the meantime, it hardcoded /dns4/, meaning that if
someone placed an ipv6 address in there things would break badly
and weirdly.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
Before we resolved all /dns*/ multiaddresses before we used them.
When using HTTPs, the Go HTTP Client only sees the resolved IP address
and it is unable to negotiate TLS with a cerficate because the request
is not going to the hostname the certificate is signed for, but to
the IP. This leverages a recent feature in go-multiaddr-net
and uses directly the user-provided hostname.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>