Skip to content

Commit

Permalink
Move api version check to header
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: rht <rhtbot@gmail.com>
  • Loading branch information
rht authored and whyrusleeping committed Dec 28, 2015
1 parent 1b889bb commit 0123971
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 68 deletions.
70 changes: 5 additions & 65 deletions cmd/ipfs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
24 changes: 23 additions & 1 deletion commands/http/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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
}
11 changes: 9 additions & 2 deletions commands/http/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down

0 comments on commit 0123971

Please sign in to comment.