From 9b18e4d8a0532a2e71aaf675f959626fa8d7d859 Mon Sep 17 00:00:00 2001 From: Dominic Della Valle Date: Tue, 13 Feb 2018 11:28:00 -0500 Subject: [PATCH] Add IPFS URL+URI parser Accept HTTP gateway URLs and IPFS URIs as arguments --- main.go | 50 ++++++++++++++++++++++++++----------- sharness/t0030-arguments.sh | 25 +++++++++++++++++++ 2 files changed, 61 insertions(+), 14 deletions(-) create mode 100755 sharness/t0030-arguments.sh diff --git a/main.go b/main.go index c094b95..ab1cb63 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,15 @@ package main import ( "fmt" + "net/url" "os" "os/signal" + gopath "path" + "path/filepath" "strings" "syscall" - path "gx/ipfs/QmT3rzed1ppXefourpmoZ7tyVQfsGPQZ1pHDngLmCvXxd3/go-path" + ipath "gx/ipfs/QmT3rzed1ppXefourpmoZ7tyVQfsGPQZ1pHDngLmCvXxd3/go-path" fallback "gx/ipfs/QmaWDhoQaV6cDyy6NSKFgPaUAGRtb4SMiLpaDYEsxP7X8P/fallback-ipfs-shell" cli "gx/ipfs/Qmc1AtgBdoUHP8oYSqU81NRYdzohmF45t5XNwVMvhCxsBA/cli" ) @@ -35,22 +38,21 @@ func main() { os.Exit(1) } - outfile := c.String("output") - arg := c.Args().First() + outPath := c.String("output") + iPath, err := parsePath(c.Args().First()) + if err != nil { + fmt.Fprintf(os.Stderr, "error: %s\n", err) + os.Exit(1) + } // Use the final segment of the object's path if no path was given. - if outfile == "" { - ipfsPath, err := path.ParsePath(arg) - if err != nil { - fmt.Fprintf(os.Stderr, "ParsePath failure: %s\n", err) - os.Exit(1) - } - segments := ipfsPath.Segments() - outfile = segments[len(segments)-1] + if outPath == "" { + trimmed := strings.TrimRight(iPath.String(), "/") + _, outPath = filepath.Split(trimmed) + outPath = filepath.Clean(outPath) } var shell fallback.Shell - var err error if c.String("node") == "fallback" { shell, err = fallback.NewShell() @@ -76,8 +78,8 @@ func main() { return nil } - if err := shell.Get(arg, outfile); err != nil { - os.Remove(outfile) + if err := shell.Get(iPath.String(), outPath); err != nil { + os.Remove(outPath) fmt.Fprintf(os.Stderr, "ipget failed: %s\n", err) os.Exit(2) } @@ -132,3 +134,23 @@ func movePostfixOptions(args []string) []string { // append extracted arguments to the real args return append(args, the_args...) } + +func parsePath(path string) (ipath.Path, error) { + ipfsPath, err := ipath.ParsePath(path) + if err == nil { // valid canonical path + return ipfsPath, nil + } + u, err := url.Parse(path) + if err != nil { + return "", fmt.Errorf("%q could not be parsed: %s", path, err) + } + + switch proto := u.Scheme; proto { + case "ipfs", "ipld", "ipns": + return ipath.ParsePath(gopath.Join("/", proto, u.Host, u.Path)) + case "http", "https": + return ipath.ParsePath(u.Path) + default: + return "", fmt.Errorf("%q is not recognized as an IPFS path") + } +} diff --git a/sharness/t0030-arguments.sh b/sharness/t0030-arguments.sh new file mode 100755 index 0000000..121ce4a --- /dev/null +++ b/sharness/t0030-arguments.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +test_description="test the ipget argument parser" + +. ./lib/sharness/sharness.sh + +test_expect_success "retrieve a known popular single file with a (HTTP) gateway URL" " + ipget http://ipfs.io/ipfs/QmQ2r6iMNpky5f1m4cnm3Yqw8VSvjuKpTcK1X7dBR1LkJF/cat.gif && + echo 'c5ea0d6cacf1e54635685803ec4edbe0d4fe8465' > expected && + shasum cat.gif | cut -d ' ' -f 1 > actual && + diff expected actual +" + +test_expect_success "retrieve a known popular single file with browser protocol URI" " + ipget ipfs://QmQ2r6iMNpky5f1m4cnm3Yqw8VSvjuKpTcK1X7dBR1LkJF/cat.gif && + echo 'c5ea0d6cacf1e54635685803ec4edbe0d4fe8465' > expected && + shasum cat.gif | cut -d ' ' -f 1 > actual && + diff expected actual +" + +test_expect_failure "don't allow non-(HTTP)gateway URLS" " + ipget ftp://ipfs.io/ipfs/QmQ2r6iMNpky5f1m4cnm3Yqw8VSvjuKpTcK1X7dBR1LkJF/cat.gif +" + +test_done