From 0123971118b5788cdf6715f6800c0c6d159fe97e Mon Sep 17 00:00:00 2001 From: rht Date: Fri, 4 Dec 2015 10:07:41 +0700 Subject: [PATCH 1/2] Move api version check to header License: MIT Signed-off-by: rht --- cmd/ipfs/main.go | 70 +++------------------------------------- commands/http/handler.go | 24 +++++++++++++- commands/http/parse.go | 11 +++++-- 3 files changed, 37 insertions(+), 68 deletions(-) diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 81d908f9c4b..97862e453ef 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -416,17 +416,13 @@ func commandShouldRunOnDaemon(details cmdDetails, req cmds.Request, root *cmds.C return nil, err } - if client != nil { // daemon is running + if client != nil { // api file exists if details.cannotRunOnDaemon { - e := "cannot use API with this command." - // check if daemon locked. legacy error text, for now. - daemonLocked, _ := fsrepo.LockedByOtherProcess(req.InvocContext().ConfigRoot) - if daemonLocked { - e = "ipfs daemon is running. please stop it to run this command" + if daemonLocked, _ := fsrepo.LockedByOtherProcess(req.InvocContext().ConfigRoot); daemonLocked { + return nil, cmds.ClientError("ipfs daemon is running. please stop it to run this command") } - - return nil, cmds.ClientError(e) + return nil, nil } return client, nil @@ -604,63 +600,7 @@ func getApiClient(repoPath, apiAddrStr string) (cmdsHttp.Client, error) { return nil, err } - client, err := apiClientForAddr(addr) - if err != nil { - return nil, err - } - - // make sure the api is actually running. - // this is slow, as it might mean an RTT to a remote server. - // TODO: optimize some way - if err := apiVersionMatches(client); err != nil { - return nil, err - } - - return client, nil -} - -// apiVersionMatches checks whether the api server is running the -// same version of go-ipfs. for now, only the exact same version of -// client + server work. In the future, we should use semver for -// proper API versioning! \o/ -func apiVersionMatches(client cmdsHttp.Client) (err error) { - ver, err := doVersionRequest(client) - if err != nil { - return err - } - - currv := config.CurrentVersionNumber - if ver.Version != currv { - return fmt.Errorf("%s (%s != %s)", errApiVersionMismatch, ver.Version, currv) - } - return nil -} - -func doVersionRequest(client cmdsHttp.Client) (*coreCmds.VersionOutput, error) { - cmd := coreCmds.VersionCmd - optDefs, err := cmd.GetOptions([]string{}) - if err != nil { - return nil, err - } - - req, err := cmds.NewRequest([]string{"version"}, nil, nil, nil, cmd, optDefs) - if err != nil { - return nil, err - } - - res, err := client.Send(req) - if err != nil { - if isConnRefused(err) { - err = repo.ErrApiNotRunning - } - return nil, err - } - - ver, ok := res.Output().(*coreCmds.VersionOutput) - if !ok { - return nil, errUnexpectedApiOutput - } - return ver, nil + return apiClientForAddr(addr) } func apiClientForAddr(addr ma.Multiaddr) (cmdsHttp.Client, error) { diff --git a/commands/http/handler.go b/commands/http/handler.go index 857b7d77a4f..df590e18c08 100644 --- a/commands/http/handler.go +++ b/commands/http/handler.go @@ -14,6 +14,7 @@ import ( cors "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors" context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "github.com/ipfs/go-ipfs/repo/config" cmds "github.com/ipfs/go-ipfs/commands" logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" @@ -35,7 +36,10 @@ type Handler struct { corsHandler http.Handler } -var ErrNotFound = errors.New("404 page not found") +var ( + ErrNotFound = errors.New("404 page not found") + errApiVersionMismatch = errors.New("api version mismatch") +) const ( StreamErrHeader = "X-Stream-Error" @@ -423,3 +427,21 @@ func allowReferer(r *http.Request, cfg *ServerConfig) bool { return false } + +// apiVersionMatches checks whether the api client is running the +// same version of go-ipfs. for now, only the exact same version of +// client + server work. In the future, we should use semver for +// proper API versioning! \o/ +func apiVersionMatches(r *http.Request) error { + clientVersion := r.UserAgent() + // skips check if client is not go-ipfs + if clientVersion == "" || !strings.Contains(clientVersion, "/go-ipfs/") { + return nil + } + + daemonVersion := fmt.Sprintf("/go-ipfs/%s/", config.CurrentVersionNumber) + if daemonVersion != clientVersion { + return fmt.Errorf("%s (%s != %s)", errApiVersionMismatch, daemonVersion, clientVersion) + } + return nil +} diff --git a/commands/http/parse.go b/commands/http/parse.go index 73af9ee5a3b..3d972db7377 100644 --- a/commands/http/parse.go +++ b/commands/http/parse.go @@ -20,12 +20,20 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) { stringArgs := make([]string, 0) + if err := apiVersionMatches(r); err != nil { + if path[0] != "version" { // compatibility with previous version check + return nil, err + } + } + cmd, err := root.Get(path[:len(path)-1]) if err != nil { // 404 if there is no command at that path return nil, ErrNotFound - } else if sub := cmd.Subcommand(path[len(path)-1]); sub == nil { + } + + if sub := cmd.Subcommand(path[len(path)-1]); sub == nil { if len(path) <= 1 { return nil, ErrNotFound } @@ -34,7 +42,6 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) { // e.g. /objects/Qabc12345 (we are passing "Qabc12345" to the "objects" command) stringArgs = append(stringArgs, path[len(path)-1]) path = path[:len(path)-1] - } else { cmd = sub } From aabf80723d5d635695ea183c4ffe67d712cd51ae Mon Sep 17 00:00:00 2001 From: rht Date: Wed, 16 Dec 2015 10:50:37 +0700 Subject: [PATCH 2/2] Move api version string to repo config License: MIT Signed-off-by: rht --- commands/http/client.go | 3 +-- commands/http/handler.go | 2 +- repo/config/version.go | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/commands/http/client.go b/commands/http/client.go index 3da268ffee9..9383e1f5d68 100644 --- a/commands/http/client.go +++ b/commands/http/client.go @@ -100,8 +100,7 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) { } else { httpReq.Header.Set(contentTypeHeader, applicationOctetStream) } - version := config.CurrentVersionNumber - httpReq.Header.Set(uaHeader, fmt.Sprintf("/go-ipfs/%s/", version)) + httpReq.Header.Set(uaHeader, config.ApiVersion) ec := make(chan error, 1) rc := make(chan cmds.Response, 1) diff --git a/commands/http/handler.go b/commands/http/handler.go index df590e18c08..6dd38616304 100644 --- a/commands/http/handler.go +++ b/commands/http/handler.go @@ -439,7 +439,7 @@ func apiVersionMatches(r *http.Request) error { return nil } - daemonVersion := fmt.Sprintf("/go-ipfs/%s/", config.CurrentVersionNumber) + daemonVersion := config.ApiVersion if daemonVersion != clientVersion { return fmt.Errorf("%s (%s != %s)", errApiVersionMismatch, daemonVersion, clientVersion) } diff --git a/repo/config/version.go b/repo/config/version.go index e672ac08ce7..d11b9d518bb 100644 --- a/repo/config/version.go +++ b/repo/config/version.go @@ -10,6 +10,8 @@ import ( // CurrentVersionNumber is the current application's version literal const CurrentVersionNumber = "0.3.11-dev" +const ApiVersion = "/go-ipfs/" + CurrentVersionNumber + "/" + // CurrentCommit is the current git commit, this is set as a ldflag in the Makefile var CurrentCommit string